├── .gitignore ├── CCOPT.COM ├── CCOPT.H ├── HELLO.COM ├── HEXTOCOM.COM ├── README.MD ├── ZSM.COM ├── ZSM.TXT ├── alloc.h ├── atexit.h ├── bsearch.h ├── c_asm.c ├── c_buf.c ├── c_cpp.c ├── c_defs.c ├── c_error.c ├── c_expr.c ├── c_iocon.c ├── c_iofile.c ├── c_main.c ├── c_parser.c ├── c_string.c ├── cc.com ├── ccopt.c ├── ccopt.rul ├── clock.h ├── conio.h ├── copying.txt ├── cpm.exe ├── cpm.h ├── cpm_player.exe ├── ctype.h ├── fileio.h ├── fprintf.h ├── hello.c ├── hextocom.c ├── make_cc.c ├── mem.h ├── mescc.h ├── mescc.txt ├── printf.h ├── qsort.h ├── rand.h ├── redir.h ├── setjmp.h ├── small_c_17 ├── -CATALOG.42- ├── AMLOAD.C ├── AMLOAD.COM ├── AMS.DOC ├── AMS.LIB ├── CCO.SUB ├── CONIO2.LIB ├── CRC.COM ├── CRCKLIST.CRC ├── CRUN2.LIB ├── CRUNLONE.LIB ├── FILE2.LIB ├── FORMAT.LIB ├── MORELIB.LIB ├── NUMIO2.LIB ├── OPT.C ├── OPT.COM ├── OPT.DOC ├── STRING.LIB ├── USQ.COM ├── WSCLEAN.C ├── WSCLEAN.COM ├── ZSC-1.CQ ├── ZSC-2.CQ ├── ZSC-C.LIB ├── ZSC.COM ├── ZSC.DOC ├── ZSM.COM └── ZSM.DOC ├── sprintf.h ├── stdbool.h ├── string.h ├── template.c ├── xprintf.h └── z80.h /.gitignore: -------------------------------------------------------------------------------- 1 | # ------------------ 2 | # INTERMEDIATE FILES 3 | # ------------------ 4 | *.HEX 5 | *.ZSM 6 | *.PRN 7 | 8 | ------------------------- 9 | # DOCUMENTATION GENERATOR 10 | # ----------------------- 11 | gdoc.com 12 | GDOC.COM 13 | 14 | # ----------------------- 15 | # PROJECT FILES & FOLDERS 16 | # ----------------------- 17 | backup/ 18 | -------------------------------------------------------------------------------- /CCOPT.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/CCOPT.COM -------------------------------------------------------------------------------- /HELLO.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/HELLO.COM -------------------------------------------------------------------------------- /HEXTOCOM.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/HEXTOCOM.COM -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | MESCC / Mike's Enhanced Small C Compiler 2 | ======================================== 3 | 4 | MESCC v1.24 - 14 Sep 2021 5 | 6 | Mike's Enhanced Small C Compiler for Z80 and CP/M 7 | 8 | Copyright (c) 1999-2021 Miguel García / FloppySoftware 9 | 10 | **MESCC** is my project of a **C compiler** for the [CP/M operating system](https://en.wikipedia.org/wiki/CP/M) and the Z80 cpu. 11 | 12 | [http://www.floppysoftware.es](http://www.floppysoftware.es) 13 | 14 | **NOTE**: This project has been extracted from my [RetroProjects](https://github.com/MiguelVis/RetroProjects) repository. 15 | 16 | Overview 17 | -------- 18 | 19 | As it is written in MESCC, it can compile itself. 20 | 21 | It is based on the version 1.7 (Oct. 1985) of [Small C](https://en.wikipedia.org/wiki/Small-C) by Ron Cain, Mike Bernson's and John Hill. 22 | 23 | MESCC outputs **Z80 assembler** code that can be assembled with **ZSM/Z80ASMUK** (supplied with MESCC), in order to build an HEX file. 24 | 25 | The HEX file can be converted to an executable COM file with LOAD (supplied with CP/M 2), HEXCOM (supplied with CP/M 3) or **HEXTOCOM** (supplied with MESCC). 26 | 27 | Also is supplied **CCOPT**, a peephole optimizer. 28 | 29 | I use MESCC for nearly all my software projects. 30 | 31 | ![MESCC image](http://www.floppysoftware.es/images/cpm-mescc.jpg "MESCC image") 32 | 33 | License 34 | ------- 35 | 36 | This program is freeware, and it's licensed under the GNU GPL license. 37 | 38 | See the file `copying.txt` for more details. 39 | 40 | About this file 41 | --------------- 42 | 43 | This file is only an introduction to MESCC. 44 | 45 | Please, read [MESCC.TXT](mescc.txt) for more information. 46 | -------------------------------------------------------------------------------- /ZSM.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/ZSM.COM -------------------------------------------------------------------------------- /alloc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file alloc.h 3 | * @brief Dynamic memory allocation. 4 | * @author Miguel I. Garcia Lopez / FloppySoftware 5 | * 6 | * Dynamic memory allocation functions, for MESCC (Mike's Enhanced 7 | * Small C Compiler for Z80 & CP/M). 8 | * 9 | * Format of each memory block: 10 | * - WORD size; size of data 11 | * - BYTE used; 0 = no, 1 = yes 12 | * - BYTE data[size]; data 13 | * 14 | * Revisions: 15 | * - 13 Dec 2000 : Last revision. 16 | * - 16 Apr 2007 : GPL'd. 17 | * - 26 Aug 2012 : Changed some things for more speed. 18 | * - 19 Feb 2015 : Now free() checks if pointer is NULL. 19 | * - 15 Aug 2016 : Optimized and documented. GPL v3. 20 | * - 21 Aug 2018 : Optimized a bit. 21 | * 22 | * Copyright (c) 1999-2016 Miguel I. Garcia Lopez / FloppySoftware. 23 | * 24 | * Licensed under the GNU General Public License v3. 25 | * 26 | * http://www.floppysoftware.es 27 | * floppysoftware@gmail.com 28 | */ 29 | #ifndef ALLOC_H 30 | 31 | #define ALLOC_H 32 | 33 | //#define XM_DEBUG 34 | 35 | #define XM_HDR_SIZE 3 // Header size of block in bytes 36 | #define XM_INI_SIZE 6 // Size in bytes needed for setup 37 | 38 | extern BYTE *ccfreefirst; 39 | extern WORD ccfreebytes; 40 | 41 | BYTE *xm_top, // First block 42 | *xm_end; // Last block 43 | 44 | /** 45 | * @fn void *malloc(unsigned int size) 46 | * @brief Allocate memory. 47 | * 48 | * This function tries to allocated a memory block of requested 49 | * size in bytes. 50 | * 51 | * The contents of the allocated memory block is undefined. 52 | * 53 | * @param size - needed size in bytes 54 | * @return pointer to allocated memory, or null pointer on failure 55 | */ 56 | malloc(size) 57 | unsigned int size; 58 | { 59 | BYTE *mptr; 60 | unsigned int msize; 61 | WORD *pw; 62 | 63 | // Setup library if needed 64 | 65 | if(!xm_top) 66 | { 67 | if(ccfreebytes > XM_INI_SIZE) 68 | { 69 | xm_top = ccfreefirst; 70 | xm_end = xm_top + ccfreebytes - XM_HDR_SIZE; 71 | 72 | // First block has all free memory 73 | *(pw = xm_top) = ccfreebytes - XM_INI_SIZE; 74 | xm_top[2] = 0; 75 | 76 | // Last block uses 0 bytes 77 | *(pw = xm_end) = 0; 78 | xm_end[2] = 1; 79 | } 80 | } 81 | 82 | // Search a free block 83 | 84 | for(mptr = xm_top; mptr != xm_end; mptr += msize + XM_HDR_SIZE) 85 | { 86 | msize = *(pw = mptr); 87 | 88 | if(!mptr[2]) 89 | { 90 | if(msize >= size) 91 | { 92 | mptr[2] = 1; 93 | 94 | if(msize >= size + XM_HDR_SIZE) 95 | { 96 | *(pw = mptr) = size; 97 | *(pw = mptr + size + XM_HDR_SIZE) = msize - size - XM_HDR_SIZE; 98 | *(mptr + size + 5) = 0; 99 | } 100 | 101 | #ifdef XM_DEBUG 102 | alloc_dbg("malloc", size); 103 | #endif 104 | return mptr + XM_HDR_SIZE; 105 | } 106 | } 107 | } 108 | 109 | #ifdef XM_DEBUG 110 | alloc_dbg("malloc", size); 111 | #endif 112 | 113 | return NULL; 114 | } 115 | 116 | /** 117 | * @fn void free(void *ptr) 118 | * @brief Deallocate memory. 119 | * 120 | * This function deallocates memory, previously allocated with malloc. 121 | * 122 | * If ptr is a null pointer, the function does nothing. 123 | * 124 | * @param ptr - memory block to deallocate 125 | */ 126 | free(ptr) 127 | BYTE *ptr; 128 | { 129 | BYTE *mptr; 130 | unsigned int msize; 131 | WORD *pw; 132 | 133 | // Do nothing on null pointer 134 | 135 | if(!ptr) 136 | return; 137 | 138 | // Make free 139 | 140 | *(ptr - 1) = 0; 141 | 142 | // Join to another free memory blocks if possible 143 | 144 | for(mptr = xm_top; mptr != xm_end; mptr += msize + XM_HDR_SIZE) 145 | { 146 | msize = *(pw = mptr); 147 | 148 | if(!mptr[2]) 149 | { 150 | if(!(*(mptr + msize + 5))) 151 | { 152 | msize += *(pw = mptr + msize + XM_HDR_SIZE) + XM_HDR_SIZE; 153 | 154 | if(!(*(mptr + msize + 5))) 155 | msize += *(pw = mptr + msize + XM_HDR_SIZE) + XM_HDR_SIZE; 156 | 157 | *(pw = mptr) = msize; 158 | 159 | break; 160 | } 161 | } 162 | } 163 | 164 | #ifdef XM_DEBUG 165 | alloc_dbg("free", ptr); 166 | #endif 167 | } 168 | 169 | #ifdef XM_DEBUG 170 | 171 | // void alloc_dbg(char *fn, WORD wrd) : Quick and dirty debug. 172 | 173 | alloc_dbg(fn, wrd) 174 | char *fn; WORD wrd; 175 | { 176 | BYTE *pb, data[4]; 177 | WORD size, *pw; 178 | int use; 179 | 180 | printf("SP = %04x (%s %04x)\n", alloc_sp(), fn, wrd); 181 | 182 | printf("Addr Size Next Use Data\n"); 183 | 184 | for(pb = xm_top; pb != xm_end; pb += size + XM_HDR_SIZE) 185 | { 186 | pw = pb; 187 | size = *pw; 188 | use = pb[2]; 189 | memcpy(data, pb + XM_HDR_SIZE, 4); 190 | 191 | printf("%04x %04x %5u %04x %s \n", pb, size, size, pb + XM_HDR_SIZE + size, use ? "Used" : "Free"); 192 | } 193 | 194 | getch(); 195 | } 196 | 197 | #asm 198 | alloc_sp 199 | LD HL,0 200 | ADD HL,SP 201 | RET 202 | #endasm 203 | 204 | #endif 205 | 206 | // Cleaning 207 | 208 | #undef XM_DEBUG 209 | #undef XM_HDR_SIZE 210 | #undef XM_INI_SIZE 211 | 212 | #endif 213 | 214 |  -------------------------------------------------------------------------------- /atexit.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file atexit.h 3 | * @brief Library for the atexit() function. 4 | * @author Miguel I. Garcia Lopez / FloppySoftware 5 | * 6 | * Support library for the atexit() function, for MESCC (Mike's Enhanced 7 | * Small C Compiler for Z80 & CP/M). 8 | * 9 | * Revisions: 10 | * - 30 Nov 2015 : First version. 11 | * - 02 Dec 2016 : Prefix private names with '_' as supported in ZSM v3.1. 12 | * - 07 Dec 2016 : GPL v3. 13 | * 14 | * Copyright (c) 2015-2016 Miguel I. Garcia Lopez / FloppySoftware. 15 | * 16 | * Licensed under the GNU General Public License v3. 17 | * 18 | * http://www.floppysoftware.es 19 | * floppysoftware@gmail.com 20 | */ 21 | #ifndef ATEXIT_H 22 | 23 | #define ATEXIT_H 24 | 25 | #define ATEXIT_MAX 3 // Max. # of allowed functions 26 | 27 | int _atexit_now; // Counter for # of stored functions 28 | WORD _atexit_arr[ATEXIT_MAX]; // Array for stored functions 29 | 30 | /** 31 | * @fn int atexit(void (*func)(void)) 32 | * @brief Register function to be called when the program terminates normally. 33 | * 34 | * This function registers a function to be called when the program 35 | * terminates normally (either with exit(), or an implicit or 36 | * explicit return in the main() function. 37 | * 38 | * The registered functions will be called in reverse order (last 39 | * registered function first). 40 | * 41 | * @param func - function to call 42 | * @return 0 on sucess, other values on failure 43 | */ 44 | int atexit(func) 45 | WORD func; 46 | { 47 | // Patch exit() 48 | 49 | #asm 50 | LD A,0CDH 51 | LD (exit),A 52 | LD HL,_exit_patch 53 | LD (exit + 1),HL 54 | #endasm 55 | 56 | if(_atexit_now < ATEXIT_MAX) { 57 | _atexit_arr[_atexit_now++] = func; return 0; 58 | } 59 | 60 | return -1; 61 | } 62 | 63 | // void _exit_patch(void) : call registered functions in reverse order. 64 | 65 | _exit_patch() 66 | { 67 | while(_atexit_now) 68 | _atexit_arr[--_atexit_now](); 69 | } 70 | 71 | // Cleaning 72 | 73 | #undef ATEXIT_MAX 74 | 75 | #endif 76 | 77 |  -------------------------------------------------------------------------------- /bsearch.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bsearch.h 3 | * @brief Binary search. 4 | * @author Miguel I. Garcia Lopez / FloppySoftware 5 | * 6 | * This library implements a binary search function of general use, 7 | * for MESCC (Mike's Enhanced Small C Compiler for Z80 & CP/M). 8 | * 9 | * Revisions: 10 | * - 30 Nov 2015 : First version. 11 | * - 15 Aug 2016 : Bug solved. Documented. GPL v3. 12 | * 13 | * Copyright (c) 2015-2016 Miguel I. Garcia Lopez / FloppySoftware. 14 | * 15 | * Licensed under the GNU General Public License v3. 16 | * 17 | * http://www.floppysoftware.es 18 | * floppysoftware@gmail.com 19 | */ 20 | #ifndef BSEARCH_H 21 | 22 | #define BSEARCH_H 23 | 24 | /** 25 | * @fn void *bsearch(const void *key, const void *base, size_t items, size_t size, int (*comp)(const void *, const void *)) 26 | * @brief Binary search. 27 | * 28 | * Search an element in an array, which must be in ascending order. 29 | * 30 | * The comparison function must return: 31 | * - <0 on key < base[x] 32 | * - =0 on key == base[x] 33 | * - >0 on key > base[x] 34 | * 35 | * @param key - element to search 36 | * @param base - address of first element 37 | * @param items - number of elements in the array 38 | * @param size - size in bytes of each element 39 | * @param comp - comparison function 40 | * @return pointer to matching element, or null pointer on failure 41 | */ 42 | BYTE *bsearch(key, base, items, size, comp) 43 | BYTE *key, *base; int items, size; WORD comp; 44 | { 45 | int a, b, c, dir; 46 | BYTE *p; 47 | 48 | a = 0; 49 | b = items - 1; 50 | 51 | while (a <= b) { 52 | 53 | c = (a + b) >> 1; // c = (a + b) / 2; 54 | p = (base + (c * size)); 55 | 56 | if (dir = comp(p, key)) { 57 | if (dir > 0) 58 | b = c - 1; 59 | else 60 | a = c + 1; 61 | } 62 | else 63 | return p; 64 | } 65 | 66 | return NULL; 67 | } 68 | 69 | #endif 70 | 71 |  -------------------------------------------------------------------------------- /c_buf.c: -------------------------------------------------------------------------------- 1 | /* c_buf.c 2 | 3 | Mike's Enhanced Small C Compiler for Z80 & CP/M 4 | 5 | I/O buffer module. 6 | 7 | Copyright (c) 1999-2016 Miguel I. Garcia Lopez, FloppySoftware. 8 | 9 | This program is free software; you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by the 11 | Free Software Foundation; either version 2, or (at your option) any 12 | later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program; if not, write to the Free Software 21 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 22 | 23 | Revisions: 24 | 25 | 16 Jan 2001 : Last revision. 26 | 16 Apr 2007 : GPL'd. 27 | 27 May 2007 : issym() expanded to more speed. 28 | Minor changes in inchar(). 29 | 16 Aug 2015 : Minor changes in BfWordEq() and BfWordNeq(). 30 | 26 Oct 2015 : Cleaned. 31 | 29 Nov 2015 : Added ChEq() y ChNeq(). 32 | 11 Oct 2016 : Documented and slightly optimized. 33 | 12 Oct 2016 : Blanks are ' ' only. See cpp_read(). 34 | */ 35 | 36 | // Test if character is valid as first character of symbol 37 | 38 | issym1st(c) 39 | char c; 40 | { 41 | return isalpha(c) || c == '_'; // FIXME - Optimize for MESCC ?? 42 | } 43 | 44 | // Test if character is valid as character symbol 45 | 46 | issym(c) 47 | char c; 48 | { 49 | return isalpha(c) || c == '_' || isdigit(c); // FIXME - Optimize for MESCC ?? 50 | } 51 | 52 | // ------------------------------------- 53 | // Functions related to the input stream 54 | // ------------------------------------- 55 | 56 | // Skip symbol name if matchs with input parameter 57 | // in: symbol name 58 | // out: true on success; else false 59 | 60 | InSymEq(s) 61 | char *s; 62 | { 63 | int i; 64 | 65 | InBlanks(); // FIXME -- Optimize this (see c_main.c) 66 | 67 | i = strlen(s); 68 | 69 | if(!memcmp(s, line + lptr, i)) 70 | { 71 | if(!issym(line[lptr + i])) 72 | { 73 | lptr += i; return 1; 74 | } 75 | } 76 | 77 | return 0; 78 | } 79 | 80 | // Skip character if matches with input parameter 81 | // in: character 82 | // out: true on success; else false 83 | 84 | InChEq(c) 85 | char c; 86 | { 87 | InBlanks(); // FIXME -- Optimize this (see c_main.c) 88 | 89 | if(BfEq(c)) // FIXME -- Optimize this 90 | { 91 | BfGet(); // FIXME -- Optimize this 92 | return 1; 93 | } 94 | 95 | return 0; 96 | } 97 | 98 | // Skip two characters if match with input parameter 99 | // in: two characters 100 | // out: true on succes; else false 101 | 102 | InWordEq(w) 103 | int w; 104 | { 105 | InBlanks(); // FIXME -- Optimize this (see c_main.c) 106 | 107 | if(BfWordEq(w)) 108 | { 109 | BfGet(); 110 | BfGet(); 111 | return 1; 112 | } 113 | 114 | return 0; 115 | } 116 | 117 | // Input byte 118 | // out: byte on success; else 0 119 | 120 | inbyte() 121 | { 122 | while(!Bf()) 123 | { 124 | if(eof) 125 | return 0; 126 | 127 | BfRead(); 128 | } 129 | 130 | return BfGet(); 131 | } 132 | 133 | // Input character 134 | // out: character on success; else 0 135 | 136 | inchar() 137 | { 138 | if(!Bf()) 139 | BfRead(); 140 | 141 | return eof ? 0 : BfGet(); 142 | } 143 | 144 | // Skip blanks 145 | 146 | InBlanks() 147 | { 148 | while(1) 149 | { 150 | /***************************** 151 | while(BfEq(' ') || BfEq('\t')) 152 | BfGet(); 153 | ******************************/ 154 | 155 | BfBlanks(); 156 | 157 | if(Bf()) 158 | break; 159 | 160 | BfRead(); 161 | 162 | if(eof) 163 | break; 164 | } 165 | } 166 | 167 | // Test if the next character matchs with input parameter 168 | 169 | ChEq(c) 170 | char c; 171 | { 172 | InBlanks(); // FIXME -- Optimize this (see c_main.c) 173 | 174 | return BfEq(c); 175 | } 176 | 177 | // Test if the next character does not match with input parameter 178 | 179 | ChNeq(c) 180 | char c; 181 | { 182 | InBlanks(); // FIXME -- Optimize this (see c_main.c) 183 | 184 | return BfNeq(c); 185 | } 186 | 187 | // ------------------------------------- 188 | // Functions related to the input buffer 189 | // ------------------------------------- 190 | 191 | Bf() 192 | { 193 | return line[lptr]; 194 | } 195 | 196 | // Return following character to the current one 197 | 198 | BfNext() 199 | { 200 | /***************************** 201 | if(Bf()) 202 | return line[lptr + 1]; 203 | 204 | return 0; 205 | ******************************/ 206 | 207 | return Bf() ? line[lptr + 1] : 0; 208 | } 209 | 210 | // Input current character 211 | 212 | BfGet() 213 | { 214 | char c; 215 | 216 | if(c = Bf()) 217 | ++lptr; 218 | 219 | return c; 220 | } 221 | 222 | // Test if current character matchs with input parameter 223 | 224 | BfEq(c) 225 | char c; 226 | { 227 | return Bf() == c; 228 | } 229 | 230 | // Test if current character does not match with input parameter 231 | 232 | BfNeq(c) 233 | char c; 234 | { 235 | return Bf() != c; 236 | } 237 | 238 | // Test if following character to the current one matchs with input parameter 239 | 240 | BfNextEq(c) 241 | char c; 242 | { 243 | return BfNext() == c; 244 | } 245 | 246 | /* 247 | int BfNextNeq(char c) 248 | Devuelve TRUE si BfNext() != c. 249 | */ 250 | 251 | // Test if following character to the current one does not match with input parameter 252 | 253 | BfNextNeq(c) 254 | char c; 255 | { 256 | return BfNext() != c; 257 | } 258 | 259 | // Test if two characters are in the current position 260 | 261 | BfWordEq(w) 262 | int w; 263 | { 264 | return w == ((Bf() << 8) + BfNext()); // FIXME -- This is not transportable at all! 265 | } 266 | 267 | // Test if two characters are not in the current position 268 | 269 | BfWordNeq(w) 270 | int w; 271 | { 272 | return w != ((Bf() << 8) + BfNext()); // FIXME -- This is not transportable at all! 273 | } 274 | 275 | // Skip blanks 276 | 277 | BfBlanks() 278 | { 279 | /******************************************************** 280 | while(BfEq(' ') || BfEq('\t')) // FIXME -- Optimize this 281 | BfGet(); 282 | *********************************************************/ 283 | 284 | while(line[lptr] == ' ') 285 | ++lptr; 286 | } 287 | 288 | // Read a line into the buffer 289 | 290 | BfRead() 291 | { 292 | eof = cpp_read(); 293 | } 294 | 295 | // Discard the current contents 296 | 297 | BfKill() 298 | { 299 | line[0] = lptr = 0; 300 | } 301 |  -------------------------------------------------------------------------------- /c_defs.c: -------------------------------------------------------------------------------- 1 | /* c_defs.c 2 | 3 | Mike's Enhanced Small C Compiler for Z80 & CP/M 4 | 5 | Definitions. 6 | 7 | Copyright (c) 1999-2021 Miguel I. Garcia Lopez, FloppySoftware. 8 | 9 | This program is free software; you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by the 11 | Free Software Foundation; either version 2, or (at your option) any 12 | later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program; if not, write to the Free Software 21 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 22 | 23 | Revisions: 24 | 25 | 17 Jan 2001 : Last revision. 26 | 16 Apr 2007 : GPL'd. 27 | 31 Jul 2014 : String pool resized to 9K (was 6000 bytes before). 28 | 31 Jul 2014 : v1.02 29 | 17 Feb 2015 : v1.03 30 | 10 Apr 2015 : v1.04 31 | 11 May 2015 : v1.05 32 | 14 Aug 2015 : v1.06 33 | 16 Aug 2015 : Removed TURBO C and PCC support. 34 | 16 Aug 2015 : v1.07 35 | 04 Sep 2015 : v1.08 36 | 28 Oct 2015 : v1.09 37 | 20 Nov 2015 : Added SY_FLAGS. Decreased local symbol table. 38 | 22 Nov 2015 : Added ERCNTAS error message. 39 | 27 Nov 2015 : Removed some text defs. 40 | 02 Dec 2015 : v1.10 41 | 08 Jan 2016 : Supported #ifs from 5 to 8. 42 | 04 Apr 2016 : v1.11 43 | 19 Jul 2016 : Removed def. ERMACUD (Macro not exist). 44 | 20 Jul 2016 : v1.12 45 | 12 Aug 2016 : v1.13 46 | 03 Oct 2016 : v1.14 47 | 11 Oct 2016 : Errors by id, instead by string. Removed #defines for help text. Documented. 48 | 13 Oct 2016 : v1.15 49 | 17 Oct 2016 : v1.16 50 | 21 Oct 2016 : v1.17 51 | 24 Oct 2016 : v1.18 52 | 13 Dec 2017 : v1.19 53 | 14 Feb 2018 : Added ERESCSQ and ERNOMEM error codes. Added C_USEMALLOC macro. 54 | v1.20 55 | 03 May 2018 : v1.21 56 | 04 Jan 2021 : v1.22 57 | 13 Jan 2021 : v1.23 58 | 14 Sep 2021 : v1.24 59 | */ 60 | 61 | // Optional #defines 62 | // ----------------- 63 | 64 | //#define C_USEPRINTF // To use printf, fprintf and sprintf 65 | #define C_USEMALLOC // To use malloc for buffers 66 | 67 | // Version 68 | // ------- 69 | 70 | #define VERSION "Mike's Enhanced Small C Compiler v1.24 - 14 Sep 2021" 71 | #define COPYRGT "(c) 1999-2021 FloppySoftware" 72 | 73 | // Output types 74 | // ------------ 75 | 76 | #define OUT_PRG 0 77 | #define OUT_LIB 1 78 | #define OUT_ASM 2 79 | 80 | // String (and array) buffer 81 | // ------------------------- 82 | 83 | #define STRBUF_SIZ 9216 84 | 85 | // Input line buffer 86 | // ----------------- 87 | 88 | #define LN_MAX 255 // Max. # of characters 89 | #define LN_SIZ 256 // Size: LN_MAX + ZERO 90 | 91 | // Symbol table format 92 | // ------------------- 93 | 94 | #define SY_NAME 0 // 12 bytes 95 | #define SY_IDENT 12 // 1 byte 96 | #define SY_TYPE 13 // 1 byte 97 | #define SY_STORAGE 14 // 1 byte 98 | #define SY_FLAGS 15 // 1 byte 99 | #define SY_OFFSET 16 // 2 bytes (1 word) 100 | 101 | #define SYMSIZE 18 // Size of a symbol table record 102 | 103 | // Symbol name 104 | #define NAME_MAX 11 // Max. # of characters 105 | #define NAME_SIZ 12 // Size: NAME_MAX + ZERO 106 | 107 | 108 | // Identity 109 | #define ID_VAR 1 // Variable 110 | #define ID_ARR 2 // Array 111 | #define ID_PTR 3 // Pointer 112 | #define ID_FUN 4 // Function 113 | 114 | // Type 115 | #define TY_CHAR 1 // 00000001b char 116 | #define TY_INT 2 // 00000010b int 117 | #define TY_UCHAR 5 // 00000101b unsigned char 118 | #define TY_UINT 6 // 00000110b unsigned int 119 | 120 | // Storage 121 | #define ST_EXTERN 1 // Extern 122 | #define ST_STATIK 2 // Global 123 | #define ST_STKLOC 3 // Local 124 | 125 | // Flags 126 | #define FL_VALUE 1 // 00000001b It has been initializated with a value 127 | #define FL_STRBF 2 // 00000010b Value is an offset to the string buffer 128 | 129 | // Symbol table storage 130 | // -------------------- 131 | 132 | // Globals 133 | #define GLB_NUM 450 // Max. # of globals 134 | #define GLB_TABSIZ 8100 // Size: GLB_NUM * SYMSIZE 135 | #define GLB_START glbsymtab 136 | 137 | #ifdef C_USEMALLOC 138 | #define GLB_END glbend 139 | #else 140 | #define GLB_END (GLB_START+GLB_TABSIZ) 141 | #endif 142 | 143 | // Locals 144 | #define LOC_NUM 32 // Max. # of locals in a function 145 | #define LOC_TABSIZ 576 // Size: LOC_NUM * SYMSIZE 146 | #define LOC_START locsymtab 147 | 148 | #ifdef C_USEMALLOC 149 | #define LOC_END locend 150 | #else 151 | #define LOC_END (LOC_START+LOC_TABSIZ) 152 | #endif 153 | 154 | // Statement types 155 | // --------------- 156 | 157 | #define S_IF 1 // if 158 | #define S_WHILE 2 // while 159 | #define S_FOR 3 // for 160 | #define S_SWITCH 4 // switch 161 | #define S_RETURN 5 // return 162 | #define S_BREAK 6 // break 163 | #define S_CONT 7 // continue 164 | #define S_EXP 8 // expression 165 | 166 | // Switch statement 167 | // ---------------- 168 | 169 | #define SWITCH_MAX 254 // Max. # of cases in a switch 170 | 171 | // While queue table format 172 | // ------------------------ 173 | 174 | #define WQ_SYM 0 // 1 word 175 | #define WQ_SP 1 // 1 word 176 | #define WQ_LOOP 2 // 1 word 177 | #define WQ_LAB 3 // 1 word 178 | #define WQ_LAB2 4 // 1 word 179 | #define WQ_END 5 // 1 word 180 | #define WQ_BODY 6 // 1 word 181 | 182 | #define WQ_TABSIZ 120 183 | #define WQ_SIZ 7 184 | #define WQ_MAX (wq+WQ_TABSIZ-WQ_SIZ) 185 | 186 | // Preprocessor 187 | // ------------ 188 | 189 | #define CPPMACSIZ 4000 // Macro table size 190 | #define CPPMAXINC 3 // Max. # of included files 191 | #define CPPMAXIFS 8 // Max. # of active #ifs 192 | #define CPPHASHSIZ 53 // Hash table size: A..Z a..z _ 193 | 194 | // Error codes 195 | // ----------- 196 | 197 | // Compiler 198 | #define ERCONST 1 // Must be constant 199 | #define ERARRSZ 2 // Illegal array size 200 | #define ERARRPT 3 // Illegal *[] 201 | #define ERCNTAS 4 // Can't assign 202 | #define ERARGNB 5 // Illegal number of arguments 203 | #define ERARGNM 6 // Need name of argument 204 | #define ERFUNDE 7 // Illegal function declaration 205 | #define ERSYMNM 8 // Illegal symbol name 206 | #define ERALDEF 9 // Already defined 207 | #define EROFGLB 10 // Global symbol table is full 208 | #define EROFLOC 11 // Local symbol table is full 209 | #define ERTMWHI 12 // Too many whiles 210 | #define ERNOWHI 13 // No active whiles 211 | #define EREXWHI 14 // Need a while 212 | #define ERLTLNG 15 // Line too long 213 | #define ERTMCAS 16 // Too many cases 214 | 215 | // Expression parser 216 | #define ERSIZOF 30 // Illegal use of sizeof 217 | #define EROFSTR 31 // String table is full 218 | #define ERILADR 32 // Illegal address 219 | #define ERCTSUB 33 // Can't index 220 | #define ERINVEX 34 // Illegal expression 221 | #define ERMBLVL 35 // Must be lvalue 222 | #define ERESCSQ 36 // Bad escape sequence 223 | 224 | // Preprocessor 225 | #define ERASMWE 50 // #asm without #endasm 226 | #define EREASWA 51 // #endasm without #asm 227 | #define ERMACAD 52 // Macro already defined 228 | #define ERTMIFS 53 // Too many active #ifs 229 | #define ERELSEW 54 // #else without #if 230 | #define ERENDIF 55 // #endif without #if 231 | #define ERBADCM 56 // Illegal # command 232 | #define EROFMAC 57 // Macro table if full 233 | #define ERTMINC 58 // Too many active includes 234 | 235 | // File I/O 236 | #define EROPEN 70 // Can't open 237 | #define ERWRITE 71 // Can't write 238 | #define ERCLOSE 72 // Can't close 239 | 240 | // Command line 241 | #define ERCMDLN 80 // Illegal option 242 | #define ERCMDER 81 // Illegal max. number of errors 243 | #define ERCMDLB 82 // Illegal label 244 | #define ERCMDST 83 // Illegal size of stack 245 | 246 | // Initialization 247 | #define ERNOMEM 90 // Not enough memory for buffers 248 | 249 |  -------------------------------------------------------------------------------- /c_error.c: -------------------------------------------------------------------------------- 1 | /* c_error.c 2 | 3 | Mike's Enhanced Small C Compiler for Z80 & CP/M 4 | 5 | Errors module. 6 | 7 | Copyright (c) 1999-2016 Miguel I. Garcia Lopez, FloppySoftware. 8 | 9 | This program is free software; you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by the 11 | Free Software Foundation; either version 2, or (at your option) any 12 | later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program; if not, write to the Free Software 21 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 22 | 23 | Revisions: 24 | 25 | 16 Jan 2001 : Last revision. 26 | 16 Apr 2007 : GPL'd. 27 | 26 Oct 2015 : Cleaned. 28 | 27 Nov 2015 : Modified some text messages. 29 | 11 Oct 2016 : Documented and slightly optimized. Errors by id or message. 30 | 14 Feb 2018 : Added errors ERESCSQ (bad escape sequence) and ERNOMEM (not enough memory for buffers). Added errinit macro. Added errinit(). 31 | */ 32 | 33 | // Need a character (it's missing) 34 | 35 | errndch(c) 36 | char c; 37 | { 38 | char s[8]; // "Need: ?" + '\0' 39 | 40 | strcpy(s, "Need: ?"); 41 | s[6] = c; 42 | 43 | errcont_str(s); 44 | } 45 | 46 | // Command line error 47 | 48 | errcmdl(id) 49 | int id; 50 | { 51 | co_str("\nError! "); co_line(errmsg(id)); 52 | exit(1); 53 | } 54 | 55 | // Initialization error 56 | errinit(id) 57 | int id; 58 | { 59 | errcmdl(id); 60 | } 61 | 62 | // File error 63 | 64 | errfile(id, fname) 65 | int id; char *fname; 66 | { 67 | co_str("\nError! File: "); co_str(fname); co_str(" - "); co_line(errmsg(id)); 68 | exit(1); 69 | } 70 | 71 | // Print error and continue 72 | 73 | errcont(id) 74 | int id; 75 | { 76 | errcont_str(errmsg(id)); 77 | } 78 | 79 | // Print error and continue 80 | 81 | errcont_str(msg) 82 | char *msg; 83 | { 84 | errshow_str(msg); 85 | 86 | if(errcnt == errmax) 87 | { 88 | co_line("\nToo many errors, compilation aborted!"); 89 | exit(1); 90 | } 91 | 92 | if(errstop) 93 | { 94 | if(getch() == '.') 95 | errstop = 0; 96 | } 97 | } 98 | 99 | // Print error and exit 100 | 101 | errexit(id) 102 | int id; 103 | { 104 | errshow(id); 105 | exit(1); 106 | } 107 | 108 | // Print error 109 | 110 | errshow(id) 111 | int id; 112 | { 113 | errshow_str(errmsg(id)); 114 | } 115 | 116 | // Print error 117 | 118 | errshow_str(msg) 119 | char *msg; 120 | { 121 | int i; 122 | 123 | fo_nl(); co_nl(); 124 | 125 | comment(); 126 | fo_str(co_str("Error!")); fo_dec(co_dec_5(++errcnt)); fo_ch(co_ch(' ')); 127 | fo_str(co_str("Line: ")); fo_dec(co_dec_5(fi_line)); fo_ch(co_ch(' ')); 128 | fo_str(co_str("File: ")); fo_line(co_line(fi_name)); 129 | 130 | comment(); 131 | fo_line(co_line(msg)); 132 | 133 | comment(); 134 | for(i = 0; line[i]; ++i) 135 | { 136 | fo_ch(co_ch(line[i] == '\t' ? ' ' : line[i])); 137 | } 138 | 139 | fo_nl(); co_nl(); 140 | 141 | comment(); 142 | for(i = 0; i < lptr; ++i) 143 | { 144 | fo_ch(co_ch(' ')); 145 | } 146 | 147 | fo_ch(co_ch('^')); 148 | fo_nl(); co_nl(); 149 | } 150 | 151 | // Return error message 152 | 153 | errmsg(id) 154 | int id; 155 | { 156 | switch(id) 157 | { 158 | // Compiler 159 | case ERCONST : return "Must be constant"; 160 | case ERARRPT : return "Illegal *[]"; 161 | case ERARRSZ : return "Illegal array size"; 162 | case ERCNTAS : return "Can't assign"; 163 | case ERARGNB : return "Illegal number of arguments"; 164 | case ERARGNM : return "Need name of argument"; 165 | case ERFUNDE : return "Illegal function declaration"; 166 | case ERSYMNM : return "Illegal symbol name"; 167 | case ERALDEF : return "Already defined"; 168 | case EROFGLB : return "Global symbol table is full"; 169 | case EROFLOC : return "Local symbol table is full"; 170 | case ERTMWHI : return "Too many whiles"; 171 | case ERNOWHI : return "No active whiles"; 172 | case EREXWHI : return "Need a while"; 173 | case ERLTLNG : return "Line too long"; 174 | case ERTMCAS : return "Too many cases"; 175 | 176 | // Expression parser 177 | case ERSIZOF : return "Illegal use of sizeof"; 178 | case EROFSTR : return "String table is full"; 179 | case ERILADR : return "Illegal address"; 180 | case ERCTSUB : return "Can't index"; 181 | case ERINVEX : return "Illegal expression"; 182 | case ERMBLVL : return "Must be lvalue"; 183 | case ERESCSQ : return "Bad escape sequence"; 184 | 185 | // Preprocessor 186 | case ERASMWE : return "#asm without #endasm"; 187 | case EREASWA : return "#endasm without #asm"; 188 | case ERMACAD : return "Macro already defined"; 189 | case ERTMIFS : return "Too many active #ifs"; 190 | case ERELSEW : return "#else without #if"; 191 | case ERENDIF : return "#endif without #if"; 192 | case ERBADCM : return "Illegal # command"; 193 | case EROFMAC : return "Macro table if full"; 194 | case ERTMINC : return "Too many active includes"; 195 | 196 | // File I/O 197 | case EROPEN : return "Can't open"; 198 | case ERWRITE : return "Can't write"; 199 | case ERCLOSE : return "Can't close"; 200 | 201 | // Command line 202 | case ERCMDLN : return "Illegal option"; 203 | case ERCMDER : return "Illegal max. number of errors"; 204 | case ERCMDLB : return "Illegal label"; 205 | case ERCMDST : return "Illegal size of stack"; 206 | 207 | // Initialization 208 | #ifdef C_USEMALLOC 209 | case ERNOMEM : return "Not enough memory for buffers"; 210 | #endif 211 | } 212 | 213 | // Unknown error id 214 | return "Unknown error"; 215 | } 216 |  -------------------------------------------------------------------------------- /c_iocon.c: -------------------------------------------------------------------------------- 1 | /* c_iocon.c 2 | 3 | Mike's Enhanced Small C Compiler for Z80 & CP/M 4 | 5 | I/O console module. 6 | 7 | Copyright (c) 1999-2016 Miguel I. Garcia Lopez, FloppySoftware. 8 | 9 | This program is free software; you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by the 11 | Free Software Foundation; either version 2, or (at your option) any 12 | later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program; if not, write to the Free Software 21 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 22 | 23 | Revisions: 24 | 25 | 16 Jan 2001 : Last revision. 26 | 16 Apr 2007 : GPL'd. 27 | 26 Oct 2015 : Cleaned. 28 | 11 Oct 2016 : Documented and slightly optimized. 29 | 21 Oct 2016 : Modified co_dec() an co_dec_5(). 30 | */ 31 | 32 | // Print a character 33 | // out: character value 34 | 35 | co_ch(c) 36 | char c; 37 | { 38 | putchar(c); return c; 39 | } 40 | 41 | // Print a string 42 | // out: string address 43 | 44 | co_str(s) 45 | char *s; 46 | { 47 | 48 | #if C_USEPRINTF 49 | printf("%s", s); 50 | #else 51 | /******************** 52 | char *p; 53 | 54 | p = s; 55 | 56 | while(*p) 57 | co_ch(*p++); 58 | *********************/ 59 | putstr(s); 60 | #endif 61 | 62 | return s; 63 | } 64 | 65 | // Print a string + '\n' 66 | // out: string address 67 | 68 | co_line(s) 69 | char *s; 70 | { 71 | #if C_USEPRINTF 72 | printf("%s\n", s); 73 | #else 74 | /*********************** 75 | co_str(s); co_ch('\n'); 76 | ***********************/ 77 | puts(s); 78 | #endif 79 | 80 | return s; 81 | } 82 | 83 | // Print '\n' 84 | 85 | co_nl() 86 | { 87 | co_ch('\n'); 88 | } 89 | 90 | // Print signed decimal number 91 | // out: value 92 | 93 | co_dec(n) 94 | int n; 95 | { 96 | #ifdef C_USEPRINTF 97 | printf("%d", n); 98 | #else 99 | /******************************************************************** 100 | int i; 101 | 102 | if(n < 0) 103 | { 104 | // Possible $8000 can't be negatived 105 | // if((number^0xFFFF)==0x7FFF){outstr("0-32768");return;} 106 | 107 | co_ch('-'); 108 | 109 | if(n == -32768) 110 | { 111 | co_str("32768"); return; 112 | } 113 | 114 | n = -n; 115 | } 116 | 117 | if(i = n / 10) 118 | co_dec(i); 119 | 120 | co_ch(n % 10 + '0'); 121 | *********************************************************************/ 122 | 123 | co_str(int2str(n)); 124 | #endif 125 | 126 | return n; 127 | } 128 | 129 | // Print signed decimal number 130 | 131 | co_dec_5(n) 132 | int n; 133 | { 134 | #ifdef C_USEPRINTF 135 | printf("%05d", n); 136 | #else 137 | /******************************************************************** 138 | if(n < 10000) 139 | { 140 | co_ch('0'); 141 | 142 | if(n < 1000) 143 | { 144 | co_ch('0'); 145 | 146 | if(n < 100) 147 | { 148 | co_ch('0'); 149 | 150 | if(n < 10) 151 | co_ch('0'); 152 | } 153 | } 154 | } 155 | 156 | co_dec(n); 157 | *********************************************************************/ 158 | 159 | co_str(int2str_5(n)); 160 | #endif 161 | } 162 |  -------------------------------------------------------------------------------- /c_iofile.c: -------------------------------------------------------------------------------- 1 | /* c_iofile.c 2 | 3 | Mike's Enhanced Small C Compiler for Z80 & CP/M 4 | 5 | I/O file module. 6 | 7 | Copyright (c) 1999-2016 Miguel I. Garcia Lopez 8 | 9 | This program is free software; you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by the 11 | Free Software Foundation; either version 2, or (at your option) any 12 | later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program; if not, write to the Free Software 21 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 22 | 23 | Revisions: 24 | 25 | 16 Jan 2001 : Last revision. 26 | 16 Apr 2007 : GPL'd. 27 | 16 Aug 2015 : Cleaned and simplified (see c_main.h). 28 | 25 Oct 2015 : Modified init_files(), fi_ch(), fo_dec(). Added some comments. 29 | 26 Oct 2015 : Moved included files control to c_cpp.c. Cleaned. 30 | 07 Nov 2015 : Modified fo_dec(). Now prints negative numbers as -32, instead of 0-32. 31 | 18 Dec 2015 : Modified fo_dec() to print -32768 correctly. 32 | 11 Oct 2016 : Documented and slightly optimized. 33 | 21 Oct 2016 : Modified fo_dec(). 34 | */ 35 | 36 | // Open file for input 37 | 38 | fi_open(fname) 39 | char *fname; 40 | { 41 | if(!(fi_fp = fopen(fname, "r"))) 42 | errfile(EROPEN, fname); 43 | 44 | strcpy(fi_name, fname); 45 | fi_line = fi_eof = 0; 46 | } 47 | 48 | // Input character from file 49 | // out: character on success, or EOF on end of file 50 | 51 | fi_ch() 52 | { 53 | return fi_eof != EOF ? (fi_eof = fgetc(fi_fp)) : EOF; 54 | } 55 | 56 | // Close input file 57 | 58 | fi_close() 59 | { 60 | if(fclose(fi_fp)) 61 | errfile(ERCLOSE, fi_name); 62 | } 63 | 64 | // Open file for output 65 | 66 | fo_open(fname) 67 | char *fname; 68 | { 69 | if(!(fo_fp=fopen(fname, "w"))) 70 | errfile(EROPEN, fname); 71 | 72 | strcpy(fo_name, fname); 73 | } 74 | 75 | // Close output file 76 | 77 | fo_close() 78 | { 79 | if(fclose(fo_fp)) 80 | errfile(ERCLOSE, fo_name); 81 | } 82 | 83 | // Output character to file 84 | 85 | fo_ch(c) 86 | int c; 87 | { 88 | if(fputc(c, fo_fp) == EOF) 89 | errfile(ERWRITE, fo_name); 90 | } 91 | 92 | // Output string to file 93 | 94 | fo_str(s) 95 | char *s; 96 | { 97 | while(*s) 98 | fo_ch(*s++); 99 | } 100 | 101 | // Output newline to file 102 | 103 | fo_nl() 104 | { 105 | fo_ch('\n'); 106 | } 107 | 108 | // Output colon to file 109 | 110 | fo_colon() 111 | { 112 | fo_ch(':'); 113 | } 114 | 115 | // Output string + newline to file 116 | 117 | fo_line(s) 118 | char *s; 119 | { 120 | fo_str(s); fo_nl(); 121 | } 122 | 123 | // Output signed decimal number to file 124 | 125 | fo_dec(n) 126 | int n; 127 | { 128 | #ifdef C_USEPRINTF 129 | fprintf(fo_fp, "%d", n); 130 | #else 131 | /*********************************************************************** 132 | int i; 133 | 134 | if(n < 0) 135 | { 136 | // Possible $8000 can't be negatived 137 | // if((number^0xFFFF)==0x7FFF){outstr("0-32768");return;} 138 | 139 | fo_ch('-'); 140 | 141 | if(n == -32768) 142 | { 143 | fo_str("32768"); return; 144 | } 145 | 146 | n = -n; 147 | } 148 | 149 | if(i = n / 10) 150 | fo_dec(i); 151 | 152 | fo_ch(n % 10 + '0'); 153 | ************************************************************************/ 154 | 155 | fo_str(int2str(n)); 156 | #endif 157 | } 158 |  -------------------------------------------------------------------------------- /c_main.c: -------------------------------------------------------------------------------- 1 | /* c_main.c 2 | 3 | Mike's Enhanced Small C Compiler for Z80 & CP/M 4 | 5 | Main module. 6 | 7 | Copyright (c) 1999-2016 Miguel I. Garcia Lopez 8 | 9 | This program is free software; you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by the 11 | Free Software Foundation; either version 2, or (at your option) any 12 | later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program; if not, write to the Free Software 21 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 22 | 23 | Revisions: 24 | 25 | 16 Jan 2001 : Minor changes. 26 | 20 Dec 2003 : Minor changes. 27 | 20 Apr 2004 : Last revision. 28 | 16 Apr 2007 : GPL'd. 29 | 14 Dec 2013 : BUG solved in dofor(): 'continue' jumped to expresion test, instead of increment expr. 30 | 10 Apr 2015 : Removed -A option (argc & argv support in mescc.h - now is managed by macro def. CC_NO_ARGS). 31 | 16 Aug 2015 : Amended some comments and messages. 32 | 26 Oct 2015 : Removed init_files() and cpp_end() calls. 33 | 20 Nov 2015 : Updated, symbol has a new field SY_FLAGS. 34 | 22 Nov 2015 : More on variable and array assignments. Cleaned a bit. 35 | Solved bug when an empty function was declared (return was not written). 36 | 26 Nov 2015 : More on array assignments. 37 | 27 Nov 2015 : Modified some text messages. 38 | 29 Nov 2015 : Modified dofor() to support forever loops: for(;;){...}. 39 | 01 Nov 2015 : Emit function labels without ':' -- see newfunc(). 40 | 11 Oct 2016 : Changes in doswtch() output to help the optimizer. Extract parser functions to c_parser.c. Documented. Optimized. 41 | 24 Oct 2016 : Option S to set default type for char to signed or unsigned. 42 | 14 Feb 2018 : Use malloc() optionally. 43 | */ 44 | 45 | // Globals 46 | // ------- 47 | 48 | #ifdef C_USEMALLOC 49 | 50 | char *glbsymtab, // Global symbol table 51 | *glbend, // End of global symbol table 52 | *glbptr; // Pointer 53 | 54 | char *locsymtab, // Local symbol table 55 | *locend, // End of local symbol table 56 | *locptr; // Pointer 57 | 58 | char *litq; // String pool 59 | int litptr; // Index 60 | 61 | #else 62 | 63 | char glbsymtab[GLB_TABSIZ], // Global symbol table 64 | *glbptr; // Pointer 65 | 66 | char locsymtab[LOC_TABSIZ], // Local symbol table 67 | *locptr; // Pointer 68 | 69 | char litq[STRBUF_SIZ]; // String pool and pointer 70 | int litptr; // Index 71 | 72 | #endif 73 | 74 | int wq[WQ_TABSIZ], // While queue 75 | *wqptr; // Pointer 76 | 77 | char line[LN_SIZ]; // Parsing line buffer 78 | int lptr; // Index 79 | 80 | int letlab, // Label letter 81 | errstop, // Pause on error? 82 | eof, // Non zero after final input 83 | ctext, // Non-zero if C source to be included as comment 84 | typout, // Output type: 0 = program, 1 = library, 2 = assembler 85 | lastst, // Type of last executed statement 86 | nxtlab, // Next label number 87 | litlab, // String pool label 88 | sptr, // Relative SP 89 | argstk, // Function arg. SP 90 | argtop, // Function arg. top SP 91 | errcnt, // Error count 92 | errmax, // Max. num. of errors, 93 | uchar, // Default type for char is unsigned? 94 | locsiz, // Size of local variables in a function 95 | stksize; // Stack size for program 96 | 97 | char ipfname[FILENAME_MAX], // Input file name 98 | opfname[FILENAME_MAX]; // Output file name 99 | 100 | // C Preprocessor 101 | // -------------- 102 | 103 | int cppinasm, // TRUE = #asm active 104 | cppincmt, // TRUE = multi-line comment active 105 | cppinign, // TRUE = #if FALSE active (ignored code) 106 | 107 | cppiflev, // #if level 108 | cppifact; // Active #if level 109 | 110 | int cppincs; // Number of active #includes 111 | WORD cppfps[CPPMAXINC]; // FPs for active includes - FILE *cppfps[x] 112 | int cpplines[CPPMAXINC]; // Number of current line for active #includes 113 | char cppfnames[45]; // Buffer for filenames == CPPMAXINC * FILENAME_MAX 114 | 115 | char cpptmp[LN_SIZ]; // Line buffer 116 | int cpptmpx; // Index to line buffer 117 | 118 | #ifdef C_USEMALLOC 119 | 120 | char *cppmac; // Macro buffer 121 | int cppmacx; // Index to macro buffer 122 | 123 | #else 124 | 125 | char cppmac[CPPMACSIZ]; // Macro buffer 126 | int cppmacx; // Index to macro buffer 127 | 128 | #endif 129 | 130 | int cpphash[CPPHASHSIZ]; // Hash for macros 131 | 132 | // File I/O 133 | // -------- 134 | 135 | // Current input file 136 | FILE *fi_fp; // File handle 137 | char fi_name[FILENAME_MAX]; // File name 138 | int fi_line; // Line number 139 | int fi_eof; // TRUE = EOF 140 | 141 | // Output file 142 | FILE *fo_fp; // File handle 143 | char fo_name[FILENAME_MAX]; // File name 144 | 145 | // Entry point to compiler 146 | // ---------------------- 147 | 148 | main(argc,argv) 149 | int argc, argv[]; // MESCC doesn't have char *argv[] yet... 150 | { 151 | // Print title, version, etc. 152 | title(); 153 | 154 | // Print help text if there are no arguments 155 | if(argc == 1) 156 | { 157 | help(); return; 158 | } 159 | 160 | #ifdef C_USEMALLOC 161 | 162 | // Alloc memory for buffers 163 | if(!(glbsymtab = malloc(GLB_TABSIZ)) || !(locsymtab = malloc(LOC_TABSIZ)) || !(litq = malloc(STRBUF_SIZ)) || !(cppmac = malloc(CPPMACSIZ))) 164 | { 165 | errinit(ERNOMEM); 166 | } 167 | 168 | glbend = glbsymtab + GLB_TABSIZ; 169 | locend = locsymtab + LOC_TABSIZ; 170 | 171 | #endif 172 | 173 | // Setup default values 174 | errstop = 1; 175 | errmax = 50; 176 | letlab = 'a'; 177 | typout = OUT_PRG; 178 | *opfname = '\0'; 179 | stksize = 512; 180 | /* Already 0 ******************* 181 | ctext = uchar = nxtlab = 0; 182 | ********************************/ 183 | 184 | // Parse options from command line 185 | getargs(argc - 1, &argv[1]); 186 | 187 | // Setup globals 188 | glbptr = GLB_START; 189 | locptr = LOC_START; 190 | wqptr = wq; 191 | litlab = getlabl(); 192 | /* Already 0 ****************************** 193 | litptr = sptr = errcnt = eof = lastst = 0; 194 | *******************************************/ 195 | 196 | // Setup files 197 | //init_files(); 198 | 199 | // Setup preprocessor 200 | cpp_start(); 201 | 202 | // Open files 203 | fi_open(ipfname); 204 | fo_open(opfname); 205 | 206 | // Send header to output file 207 | a_start(); 208 | 209 | // Process all input 210 | parse(); 211 | 212 | // Print \n 213 | co_nl(); 214 | 215 | // Dump string literals 216 | dmplits(); 217 | 218 | // Dump globals 219 | dmpglbs(); 220 | 221 | // Send footer to output file 222 | a_end(); 223 | 224 | // Close files 225 | fo_close(); 226 | fi_close(); 227 | 228 | // Say good bye to the C preprocessor 229 | //cpp_end(); 230 | 231 | // Print \n 232 | co_nl(); 233 | 234 | // Print summary 235 | co_line("Table Used Free"); 236 | co_line("-------- ----- -----"); 237 | co_str("Strings "); co_dec_5(litptr) ;co_ch(' '); co_dec_5(STRBUF_SIZ - litptr); co_nl(); 238 | co_str("Globals "); co_dec_5(glbptr - GLB_START); co_ch(' '); co_dec_5(GLB_END - glbptr); co_nl(); 239 | co_str("Macros "); co_dec_5(cppmacx) ;co_ch(' '); co_dec_5(CPPMACSIZ - cppmacx); co_nl(); 240 | 241 | co_nl(); 242 | 243 | co_str("Errors: "); co_dec(errcnt); co_nl(); 244 | co_str("Next label: "); co_ch(letlab); co_dec(nxtlab); co_nl(); 245 | } 246 | 247 | // Parse options from command line 248 | 249 | getargs(argcnt, argstr) 250 | int argcnt, argstr[]; 251 | { 252 | int i; 253 | char *ptr, *ptr3, *ptr4; 254 | 255 | // Input file name 256 | strcpy(ipfname, argstr[0]); 257 | 258 | // Parse options from command line 259 | for(i = 1; i < argcnt; ++i) 260 | { 261 | ptr = strupr(argstr[i]); // FIXME - This is for some emulators which not convert command line to upper case (!) 262 | 263 | // -O:AB 264 | ptr3 = ptr + 3; // Pointer to A 265 | ptr4 = ptr + 4; // Pointer to B 266 | 267 | if(*ptr++ != '-') 268 | errcmdl(ERCMDLN); 269 | 270 | // Output file name 271 | if((!memcmp("O:", ptr, 2)) && *ptr3) 272 | strcpy(opfname, ptr3); 273 | 274 | // Output file type 275 | else if(!strcmp("PRG", ptr)) 276 | typout = OUT_PRG; 277 | else if(!strcmp("LIB", ptr)) 278 | typout = OUT_LIB; 279 | else if(!strcmp("ASM", ptr)) 280 | typout = OUT_ASM; 281 | 282 | // Write C source as comments? 283 | else if(!strcmp("C+", ptr)) 284 | ctext = 1; 285 | else if(!strcmp("C-", ptr)) 286 | ctext = 0; 287 | 288 | // Pause on errors? 289 | else if(!strcmp("E+", ptr)) 290 | errstop = 1; 291 | else if(!strcmp("E-", ptr)) 292 | errstop = 0; 293 | 294 | // Default type for char is unsigned? 295 | else if(!strcmp("S+", ptr)) 296 | uchar = 0; 297 | else if(!strcmp("S-", ptr)) 298 | uchar = 1; 299 | 300 | // Max. number of errors to abort compilation 301 | else if((!memcmp("E:", ptr, 2)) && *ptr3) 302 | { 303 | if((errmax = atoi(ptr3)) < 0) 304 | errcmdl(ERCMDER); 305 | } 306 | 307 | // Letter and start number for labels 308 | else if((!memcmp("L:", ptr, 2)) && *ptr3 && *ptr4) 309 | { 310 | if(!isalpha((letlab = *ptr3)) || (nxtlab = atoi(*ptr4)) < 0) 311 | errcmdl(ERCMDLB); 312 | } 313 | 314 | // Stack size 315 | else if((!memcmp("S:", ptr, 2)) && *ptr3) 316 | { 317 | if((stksize = atoi(ptr3)) < 512) 318 | errcmdl(ERCMDST); 319 | } 320 | 321 | // Unknown option 322 | else 323 | errcmdl(ERCMDLN); 324 | } 325 | 326 | // Add type to input file name if needed 327 | if(!strchr(ipfname, '.')) 328 | strcat(ipfname, ".c"); 329 | 330 | // Add name without type to output file name if needed 331 | if(!(*opfname)) 332 | { 333 | strcpy(opfname, ipfname); 334 | ptr = strchr(opfname, '.'); 335 | *ptr = 0; 336 | } 337 | 338 | // Add type to output file name if needed 339 | if(!strchr(opfname, '.')) 340 | strcat(opfname, typout == OUT_LIB ? ".lib" : ".zsm"); 341 | } 342 | 343 | // Print title, version, etc. 344 | 345 | title() 346 | { 347 | co_line(VERSION); co_nl(); 348 | co_line(COPYRGT); co_nl(); 349 | } 350 | 351 | // Print help text 352 | 353 | help() 354 | { 355 | co_line("Usage: cc name[.typ] [options]\n"); 356 | co_line("-PRG Out normal file ---- Type=ZSM"); 357 | co_line("-LIB Out library file --- Type=LIB"); 358 | co_line("-ASM Out assembler file - Type=ZSM"); 359 | co_line("-O:name[.typ] File name for output"); 360 | co_line("-Cflag C source as comments?"); 361 | co_line("-Eflag Pause on errors?"); 362 | co_line("-Sflag Default type for char is signed?"); 363 | co_line("-E:number Max. number of errors to abort"); 364 | co_line("-L:letnum Letter and start number for labels"); 365 | co_line("-S:size Mininum stack size\n"); 366 | co_line("Default options are: (flag is + for YES, - for NO)\n"); 367 | co_line("\t-PRG -C- -E+ -S+ -E:50 -L:A0 -S:512"); 368 | co_line("\tInput file type is .c"); 369 | co_line("\tOutput file name is the same as input"); 370 | } 371 |  -------------------------------------------------------------------------------- /c_string.c: -------------------------------------------------------------------------------- 1 | /* c_string.c 2 | 3 | Mike's Enhanced Small C Compiler for Z80 & CP/M 4 | 5 | String handling module. 6 | 7 | Copyright (c) 1999-2016 Miguel I. Garcia Lopez, FloppySoftware. 8 | 9 | This program is free software; you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by the 11 | Free Software Foundation; either version 2, or (at your option) any 12 | later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program; if not, write to the Free Software 21 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 22 | 23 | Revisions: 24 | 25 | 20 Oct 2016 : Documented and slightly optimized. Added int2str_5(). 26 | */ 27 | 28 | // Private globals for this module 29 | 30 | char cc_str[7]; // -12345 + ZERO 31 | 32 | // Output int as signed decimal number 33 | 34 | int2str(n) 35 | int n; 36 | { 37 | #ifdef C_USEPRINTF 38 | sprintf(cc_str, "%d", n); 39 | 40 | return cc_str; 41 | #else 42 | char *p; 43 | int sign; 44 | 45 | if(n >= 0) 46 | { 47 | sign = 0; 48 | } 49 | else if(n != -32768) 50 | { 51 | sign = 1; 52 | n = -n; 53 | } 54 | else 55 | { 56 | return strcpy(cc_str, "-32768"); 57 | } 58 | 59 | *(p = cc_str + 6) = '\0'; 60 | 61 | do 62 | { 63 | *(--p) = '0' + n % 10; 64 | } while((n /= 10)); 65 | 66 | if(sign) 67 | { 68 | *(--p) = '-'; 69 | } 70 | 71 | return p; 72 | #endif 73 | } 74 | 75 | // Output int as signed decimal number, 5 digits, padded with spaces. 76 | 77 | int2str_5(n) 78 | int n; 79 | { 80 | #ifdef C_USEPRINTF 81 | sprintf(cc_str, "%5d", n); 82 | 83 | return cc_str; 84 | #else 85 | char *p; 86 | int i, k; 87 | 88 | k = 5 - strlen((p = int2str(n))); 89 | 90 | for(i = 0; i < k; ++i) 91 | { 92 | cc_str[i] = ' '; 93 | } 94 | 95 | strcpy(cc_str + i, p); 96 | 97 | return cc_str; 98 | #endif 99 | } 100 | 101 |  -------------------------------------------------------------------------------- /cc.com: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/cc.com -------------------------------------------------------------------------------- /clock.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file clock.h 3 | * @brief Date & time functions for CP/M Plus. 4 | * @author Miguel I. Garcia Lopez / FloppySoftware 5 | * 6 | * Date & time functions for CP/M Plus, for MESCC (Mike's Enhanced 7 | * Small C Compiler for Z80 & CP/M). 8 | * 9 | * Defined macros: 10 | * - CLOCK_LEN - size of clk array in bytes 11 | * - DATE_LEN - size of dt array in words 12 | * 13 | * CP/M clock array - BYTE clk[CLOCK_LEN]: 14 | * - BYTE day-low-byte Day 1 is Sunday, 1 Jan 1978 15 | * - BYTE day-high-byte 16 | * - BYTE hour BCD 17 | * - BYTE minute BCD 18 | * - BYTE second BCD 19 | * 20 | * Date array - WORD dt[DATE_LEN]: 21 | * - WORD year 22 | * - WORD month = 0 is January, 1 is February, etc. 23 | * - WORD day 24 | * - WORD hour 25 | * - WORD minute 26 | * - WORD second 27 | * - WORD weekday = 0 is Sunday, 1 is Monday, etc. 28 | * 29 | * Revisions: 30 | * - 07 Apr 2015 : 1st version. 31 | * - 23 Apr 2015 : Solved bug in setdate() - bad check in day. 32 | * - 15 Aug 2016 : Documented. GPL v3. 33 | * 34 | * Copyright (c) 2015-2016 Miguel I. Garcia Lopez / FloppySoftware. 35 | * 36 | * Licensed under the GNU General Public License v3. 37 | * 38 | * http://www.floppysoftware.es 39 | * floppysoftware@gmail.com 40 | */ 41 | #ifndef CLOCK_H 42 | 43 | #define CLOCK_H 44 | 45 | char xd_mdays[] = { // Days per month 46 | 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 47 | }; 48 | 49 | #define CLOCK_LEN 5 // CP/M clock array lenght in BYTES - ie: unsigned char clk[5] 50 | #define DATE_LEN 7 // Date array lenght in WORDS - ie: int dt[7] 51 | 52 | /** 53 | * @fn unsigned char *getclock(unsigned char *clk) 54 | * @brief Get CP/M clock. 55 | * 56 | * This function fills the clk array with the current CP/M clock values. 57 | * 58 | * @param clk - pointer to clock array 59 | * @return pointer to clk 60 | */ 61 | getclock(clk) 62 | unsigned char *clk; 63 | { 64 | // CP/M fills day, hour & minute; the A register holds the second. 65 | 66 | clk[4] = bdos_a(105, clk); 67 | 68 | return clk; 69 | } 70 | 71 | /** 72 | * @fn void setclock(unsigned char *clk) 73 | * @brief Set CP/M clock. 74 | * 75 | * This function sets the CP/M clock with the values in clk. 76 | * 77 | * @param clk - pointer to clock array 78 | */ 79 | setclock(clk) 80 | unsigned char *clk; 81 | { 82 | unsigned char b[8]; 83 | int i; 84 | 85 | // We don't use the BDOS function, because it resets the seconds to 0 86 | 87 | // Disable interrupts to avoid unwanted clock changes 88 | 89 | #asm 90 | di 91 | #endasm 92 | 93 | // Set the clock fields in SCB 94 | 95 | b[1] = 0xFF; // Set byte 96 | 97 | for(i = 0; i < 5; ++i) 98 | { 99 | b[0] = 0x58 + i; b[2] = clk[i]; bdos_a(49, b); 100 | } 101 | 102 | // Tell the BIOS that we have changed the clock 103 | 104 | b[0] = 26; b[2] = 0xFF; bdos_a(50, b); 105 | 106 | // Enable interrupts 107 | 108 | #asm 109 | ei 110 | #endasm 111 | 112 | } 113 | 114 | /** 115 | * @fn int *getdate(unsigned char *clk, int *dt) 116 | * @brief Return date values from clock values. 117 | * 118 | * This funcion converts CP/M clock values to date values. 119 | * 120 | * @param clk - pointer to clock array 121 | * @param dt - pointer to date array 122 | * @return pointer to dt 123 | */ 124 | getdate(clk, dt) 125 | unsigned char *clk; int *dt; 126 | { 127 | unsigned int date; 128 | int year, month, leap, wday; 129 | 130 | // Get days from CP/M clock 131 | 132 | date = clk[0] + (clk[1] << 8); 133 | 134 | // Compute weekday: 0 is Sunday, 1 is Monday, etc. 135 | 136 | wday = (date + 6) % 7; 137 | 138 | // Compute year 139 | 140 | for(year = 1978; date >= 365 + (leap = xd_isleap(year)); ++year) 141 | date -= (365 + leap); 142 | 143 | // Set days for February 144 | 145 | xd_mdays[1] = 28 + leap; 146 | 147 | // Compute month 148 | 149 | for(month = 0; date >= xd_mdays[month]; ++month) 150 | date -= xd_mdays[month]; 151 | 152 | // Now, date has the day 153 | 154 | // Set date array fields 155 | 156 | dt[0] = year; // year 157 | dt[1] = month; // month 158 | dt[2] = date; // day 159 | dt[3] = xd_getbcd(clk[2]); // hour 160 | dt[4] = xd_getbcd(clk[3]); // minute 161 | dt[5] = xd_getbcd(clk[4]); // second 162 | dt[6] = wday; // Weekday 163 | 164 | // Return date array 165 | 166 | return dt; 167 | } 168 | 169 | /** 170 | * @fn unsigned char *setdate(unsigned char *clk, int *dt) 171 | * @brief Return clock values from date values. 172 | * 173 | * This funcion converts date values into CP/M clock values. 174 | * 175 | * @param clk - pointer to clock array 176 | * @param dt - pointer to date array 177 | * @return pointer to clk, or NULL on failure 178 | */ 179 | setdate(clk, dt) 180 | unsigned char *clk; int *dt; 181 | { 182 | unsigned int days; 183 | int i; 184 | 185 | // Check year and month 186 | 187 | if(dt[0] < 1978 || dt[0] > 2150 || dt[1] < 0 || dt[1] > 11) 188 | return NULL; 189 | 190 | // Set days for February 191 | 192 | xd_mdays[1] = 28 + xd_isleap(dt[0]); 193 | 194 | // Check day 195 | 196 | if(dt[2] < 1 || dt[2] > xd_mdays[dt[1]]) 197 | return NULL; 198 | 199 | // Check hour, minute and second 200 | 201 | if(dt[3] < 0 || dt[3] > 23 || dt[4] < 0 || dt[4] > 59 || dt[5] < 0 || dt[5] > 59) 202 | return NULL; 203 | 204 | // Compute CP/M days 205 | 206 | days = 0; 207 | 208 | for(i = 1978; i < dt[0]; ++i) 209 | days += (365 + xd_isleap(i)); 210 | 211 | for(i = 0; i < dt[1]; ++i) 212 | days += xd_mdays[i]; 213 | 214 | days += dt[2]; 215 | 216 | // Set array 217 | 218 | clk[0] = days & 0xFF; 219 | clk[1] = (days >> 8) & 0xFF; 220 | clk[2] = xd_setbcd(dt[3]); 221 | clk[3] = xd_setbcd(dt[4]); 222 | clk[4] = xd_setbcd(dt[5]); 223 | 224 | // Success 225 | 226 | return clk; 227 | } 228 | 229 | // int xd_isleap(int year) : return 1 if year is leap, else 0. 230 | 231 | xd_isleap(year) 232 | int year; 233 | { 234 | if(!(year % 4)) 235 | { 236 | if(year % 100) 237 | return 1; 238 | 239 | if(!(year % 400)) 240 | return 1; 241 | } 242 | 243 | return 0; 244 | } 245 | 246 | // int xd_getbcd(int bcd) : convert a BCD date field to an integer. 247 | 248 | xd_getbcd(bcd) 249 | int bcd; 250 | { 251 | return (bcd >> 4) * 10 + (bcd & 0x0F); 252 | } 253 | 254 | // int xd_setbcd(int i) : convert an integer to a BCD date field. 255 | 256 | xd_setbcd(i) 257 | int i; 258 | { 259 | return ((i / 10) << 4) + (i % 10); 260 | } 261 | 262 | #endif 263 | 264 |  -------------------------------------------------------------------------------- /conio.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file conio.h 3 | * @brief Console I/O. 4 | * @author Miguel I. Garcia Lopez / FloppySoftware 5 | * 6 | * Console I/O functions, for MESCC (Mike's Enhanced 7 | * Small C Compiler for Z80 & CP/M). 8 | * 9 | * Supports following #defines: 10 | * - CC_STDIO Support for stdin, stdout & stderr. 11 | * - CC_CONIO_BIOS Support for direct console I/O. 12 | * 13 | * Revisions: 14 | * - 22 Jan 2001 : Last revision. 15 | * - 16 Apr 2007 : GPL'd. 16 | * - 21 Apr 2007 : Changed puts for ANSI compatibility. 17 | * - 15 May 2007 : Bug solved - added LF output to puts. 18 | * - 13 Jul 2014 : Added kbhit(). 19 | * - 08 Dec 2014 : Added support for stdin, stdout & stderr. 20 | * - 31 Dec 2014 : Solved bug in putstr when characters are > 0x7F. 21 | * - 20 Dec 2015 : Added macro CC_CONIO_BIOS to support direct console I/O using BIOS, instead of BDOS. 22 | * - 08 Jan 2015 : Modified getch() when access BDOS (fn. 6 instead of 1). 23 | * - 10 Dec 2016 : Documented. GPL v3. 24 | * 25 | * Copyright (c) 1999-2016 Miguel I. Garcia Lopez / FloppySoftware. 26 | * 27 | * Licensed under the GNU General Public License v3. 28 | * 29 | * http://www.floppysoftware.es 30 | * floppysoftware@gmail.com 31 | */ 32 | #ifndef CONIO_H 33 | 34 | #define CONIO_H 35 | 36 | /** 37 | * @fn int putch(int ch) 38 | * @brief Send character to the console. 39 | * @param ch - character 40 | * @return ch 41 | */ 42 | #ifdef CC_CONIO_BIOS 43 | #asm 44 | 45 | putch 46 | PUSH HL 47 | LD C,L 48 | LD E,9 49 | CALL xbios 50 | POP HL 51 | RET 52 | 53 | xbios 54 | LD HL,(1) 55 | LD D,0 56 | ADD HL,DE 57 | JP (HL) 58 | 59 | #endasm 60 | #else 61 | #asm 62 | 63 | putch 64 | PUSH HL 65 | LD C,2 66 | LD E,L 67 | CALL 5 68 | POP HL 69 | RET 70 | #endasm 71 | #endif 72 | 73 | /** 74 | * @fn int getch(void) 75 | * @brief Get character from the console without echo. 76 | * 77 | * Waits until a character is available. 78 | * 79 | * @return character 80 | */ 81 | #ifdef CC_CONIO_BIOS 82 | #asm 83 | 84 | getch 85 | LD E,6 86 | CALL xbios 87 | LD H,0 88 | LD L,A 89 | RET 90 | 91 | #endasm 92 | #else 93 | #asm 94 | 95 | getch 96 | LD C,6 97 | LD E,255 98 | CALL 5 99 | OR A 100 | JR Z,getch 101 | LD H,0 102 | LD L,A 103 | RET 104 | #endasm 105 | #endif 106 | 107 | /** 108 | * @fn int kbhit(void) 109 | * @brief Tests console input status. 110 | * @return != 0 if a character is available, else 0. 111 | */ 112 | #ifdef CC_CONIO_BIOS 113 | #asm 114 | 115 | kbhit 116 | LD E, 3 117 | CALL xbios 118 | LD H,A 119 | LD L,A 120 | RET 121 | 122 | #endasm 123 | #else 124 | #asm 125 | 126 | kbhit 127 | LD C,11 128 | CALL 5 129 | LD H,A 130 | LD L,A 131 | RET 132 | #endasm 133 | #endif 134 | 135 | /** 136 | * @fn int getchar(void) 137 | * @brief Get character from the console or stdin. 138 | * 139 | * Waits until a character is available. 140 | * 141 | * #ifdef CC_STDIO: Returns a character from stdin, or EOF on end of file or error. 142 | * #ifndef CC_STDIO: Returns a character from the console. Echoes the character. 143 | * 144 | * @return character on success, else EOF. 145 | */ 146 | getchar() 147 | { 148 | 149 | #ifdef CC_STDIO 150 | 151 | return fgetc(stdin); 152 | 153 | #else 154 | 155 | return putchar(getch()); 156 | 157 | #endif 158 | 159 | } 160 | 161 | /** 162 | * @fn int putchar(int ch) 163 | * @brief Send character to the console or stdout. 164 | * 165 | * #ifdef CC_STDIO: Returns ch, or EOF on error. 166 | * #ifndef CC_STDIO: Returns ch. 167 | * 168 | * @param ch - character 169 | * @return ch on success, else EOF. 170 | */ 171 | putchar(ch) 172 | int ch; 173 | { 174 | 175 | #ifdef CC_STDIO 176 | 177 | return fputc(ch, stdout); 178 | 179 | #else 180 | 181 | if(ch == '\n') 182 | putch('\r'); 183 | 184 | return putch(ch); 185 | 186 | #endif 187 | 188 | } 189 | 190 | /** 191 | * @fn int putstr(char *s) 192 | * @brief Send string to the console or stdout. 193 | * 194 | * #ifdef CC_STDIO: Returns the number of characters sent, or EOF on error. 195 | * #ifndef CC_STDIO: Returns a non-negative value to indicate success. 196 | * 197 | * @param s - string 198 | * @return number of characters sent on success, else EOF. 199 | */ 200 | putstr(s) 201 | char *s; 202 | { 203 | 204 | #ifdef CC_STDIO 205 | 206 | /* FIXME : Better if call to fputs (if available) */ 207 | 208 | int i, c; 209 | 210 | i = 0; 211 | 212 | while(*s) 213 | { 214 | /* FIXME : -1 hardcoded -- < 0 causes strange 215 | behaviour if ch > 0x7F */ 216 | 217 | if((c = putchar(*s++)) == -1) 218 | return c; 219 | ++i; 220 | } 221 | 222 | return i; 223 | #else 224 | while(*s) 225 | putchar(*s++); 226 | 227 | return 0; 228 | #endif 229 | 230 | } 231 | 232 | /** 233 | * @fn int puts(char *s) 234 | * @brief Send string + '\n' to the console or stdout. 235 | * 236 | * #ifdef CC_STDIO: Returns the number of characters sent, or EOF on error. 237 | * #ifndef CC_STDIO: Returns a non-negative value to indicate success. 238 | * 239 | * @param s - string 240 | * @return number of characters sent on success, else EOF. 241 | */ 242 | puts(s) 243 | char *s; 244 | { 245 | putstr(s); 246 | 247 | return putchar('\n'); /* FIXME */ 248 | } 249 | 250 | #endif 251 | 252 |  -------------------------------------------------------------------------------- /cpm.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/cpm.exe -------------------------------------------------------------------------------- /cpm.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cpm.h 3 | * @brief CP/M functions. 4 | * @author Miguel I. Garcia Lopez / FloppySoftware 5 | * 6 | * CP/M functions for MESCC (Mike's Enhanced 7 | * Small C Compiler for Z80 & CP/M). 8 | * 9 | * Supports following #defines: 10 | * - CC_FCX To support FCX (user number in file names). 11 | * - CC_FCX_DIR To support named directories in file names. 12 | * 13 | * When CC_FCX_DIR is defined, you must supply a function that 14 | * translates a directory name (string in upper case, up to 8 15 | * characters in length + ZERO), into a drive & user number 16 | * specification (string in upper case, up to 3 characters in 17 | * length + ZERO): 18 | * 19 | * char *DirToDrvUsr(char *s) 20 | * 21 | * ie - DirToDrvUsr("ROOT") == "A0" 22 | * 23 | * It must to return NULL on unknown directory names. 24 | * 25 | * See UxGetDrvUsr() for an example. 26 | * 27 | * Definitions for BDOS functions: 28 | * - BF_GETDRV 25 29 | * - BF_SETDRV 14 30 | * - BF_USER 32 31 | * - BF_DMA 26 32 | * - BF_FIND1ST 17 33 | * - BF_FINDNEXT 18 34 | * - BF_OSVER 12 35 | * - BF_CONST 11 36 | * - BF_FSIZE 35 37 | * - BF_OPEN 15 38 | * - BF_DELETE 19 39 | * - BF_CREATE 22 40 | * - BF_READSEQ 20 41 | * - BF_WRITESEQ 21 42 | * - BF_RENAME 23 43 | * - BF_CLOSE 16 44 | * - BF_ATTRIB 30 45 | * - BF_READRND 33 46 | * - BF_WRITERND 34 47 | * 48 | * Revisions: 49 | * - 19 Oct 2000 : Last revision. 50 | * - 17 Apr 2004 : Added renfile function. 51 | * - 16 Apr 2007 : GPL'd. 52 | * - 12 Dec 2014 : Added FCX support. 53 | * - 11 Feb 2015 : Added some BDOS #defines. 54 | * - 03 Sep 2015 : Added FCX_DIR support (names for user areas, a sort of alias). 55 | * - 08 Jan 2016 : Include ctype.h, mem.h libraries if CC_FCX is defined. 56 | * - 18 Jul 2016 : Added #defines BF_READRND and BF_WRITERND. 57 | * - 11 Dec 2016 : Documented. Optimized. GPL v3. 58 | * 59 | * Copyright (c) 1999-2021 Miguel I. Garcia Lopez / FloppySoftware. 60 | * 61 | * Licensed under the GNU General Public License v3. 62 | * 63 | * http://www.floppysoftware.es 64 | * floppysoftware@gmail.com 65 | */ 66 | #ifndef CPM_H 67 | 68 | #define CPM_H 69 | 70 | // Dependencies 71 | // ------------ 72 | 73 | #ifdef CC_FCX 74 | 75 | #ifndef CTYPE_H 76 | #include 77 | #endif 78 | 79 | #ifndef MEM_H 80 | #include 81 | #endif 82 | 83 | #endif 84 | 85 | // BDOS FUNCTIONS 86 | // -------------- 87 | 88 | #define BF_GETDRV 25 89 | #define BF_SETDRV 14 90 | #define BF_USER 32 91 | #define BF_DMA 26 92 | #define BF_FIND1ST 17 93 | #define BF_FINDNEXT 18 94 | #define BF_OSVER 12 95 | #define BF_CONST 11 96 | #define BF_FSIZE 35 97 | #define BF_OPEN 15 98 | #define BF_DELETE 19 99 | #define BF_CREATE 22 100 | #define BF_READSEQ 20 101 | #define BF_WRITESEQ 21 102 | #define BF_RENAME 23 103 | #define BF_CLOSE 16 104 | #define BF_ATTRIB 30 105 | #define BF_READRND 33 106 | #define BF_WRITERND 34 107 | 108 | /** 109 | * @fn unsigned int bdos_hl(unsigned int bc, unsigned int de) 110 | * @brief Call to BDOS. 111 | * @param bc - bc register 112 | * @param de - de register 113 | * @return value of hl register 114 | */ 115 | #asm 116 | 117 | bdos_hl 118 | POP HL 119 | POP DE 120 | POP BC 121 | PUSH BC 122 | PUSH DE 123 | PUSH HL 124 | JP 5 125 | #endasm 126 | 127 | /** 128 | * @fn unsigned char bdos_a(unsigned int bc, unsigned int de) 129 | * @brief Call to BDOS. 130 | * @param bc - bc register 131 | * @param de - de register 132 | * @return value of a register 133 | */ 134 | #asm 135 | 136 | bdos_a 137 | POP HL 138 | POP DE 139 | POP BC 140 | PUSH BC 141 | PUSH DE 142 | PUSH HL 143 | CALL 5 144 | LD H,0 145 | LD L,A 146 | RET 147 | #endasm 148 | 149 | 150 | // FCX functions 151 | // ------------- 152 | 153 | #ifdef CC_FCX 154 | 155 | #define UX_FCX_SIZ 37 156 | #define UX_FCX_USR 0 157 | #define UX_FCX_DRV 1 158 | #define UX_FCX_RRC 34 /* Random Record Number */ 159 | 160 | /** 161 | * @fn unsigned char bdos_fcx_a(unsigned int bc, unsigned int de) 162 | * @brief Call to BDOS with a FCX as parameter. 163 | * 164 | * This function is available if CC_FCX is defined. 165 | * 166 | * @param bc - bc register 167 | * @param de - de register 168 | * @return value of a register 169 | */ 170 | bdos_fcx_a(fun, fcx) 171 | int fun; BYTE *fcx; 172 | { 173 | int val, old_user; 174 | 175 | if(*fcx) 176 | { 177 | if((old_user = bdos_a(BF_USER, 0xFFFF)) != *fcx - 1) 178 | { 179 | bdos_a(BF_USER, *fcx - 1); /* Set user to FCX user */ 180 | val = bdos_a(fun, fcx + 1); /* Call BDOS function */ 181 | bdos_a(BF_USER, old_user); /* Set old user */ 182 | 183 | return val; 184 | } 185 | } 186 | 187 | return bdos_a(fun, fcx + 1); 188 | } 189 | 190 | /* ----------------------------------------------------- 191 | This is an example, you must define your own funcion. 192 | ----------------------------------------------------- 193 | 194 | char *DirToDrvUsr(char *s) 195 | 196 | Translate a directory name in upper case, to a drive 197 | and user name specification in upper case. 198 | 199 | Return NULL on unknown directory name. 200 | 201 | DirToDrvUsr(s) 202 | char *s; 203 | { 204 | if(!strcmp(s, "ROOT")) 205 | return "A0"; 206 | else if(!strcmp(s, "MESCC")) 207 | return "A1"; 208 | else if(!strcmp(s, "TEMP")) 209 | return "M0"; 210 | 211 | return NULL; 212 | } 213 | ----------------------------------------------------- 214 | */ 215 | 216 | /** 217 | * @fn int setfcx(char *fname, char *fcx) 218 | * @brief Make FCX. 219 | * 220 | * This function is available if CC_FCX is defined. 221 | * 222 | * @param fname - filename 223 | * @param fcx - destination FCX 224 | * @return 0 on success, else != 0 225 | */ 226 | setfcx(s, fcx) 227 | char *s; BYTE *fcx; 228 | { 229 | char f[9]; WORD path; BYTE drv, usr; 230 | 231 | memset(fcx, 0, UX_FCX_SIZ); 232 | 233 | s = UxField(s, f); 234 | 235 | if(*s == ':' && *f) 236 | { 237 | if((path = UxGetDrvUsr(f)) == -1) 238 | return -1; 239 | 240 | drv = (path >> 8) & 0xFF; 241 | usr = path & 0xFF; 242 | 243 | fcx[UX_FCX_DRV] = (drv == 0xDD ? 0 : drv + 1); 244 | fcx[UX_FCX_USR] = (usr == 0xDD ? 0 : usr + 1); 245 | 246 | s = UxField(++s, f); 247 | } 248 | 249 | if((!(*s) || *s=='.') && *f) 250 | { 251 | if(UxPad(f, fcx + 2, 8)) 252 | return -1; 253 | 254 | if(*s) 255 | s = UxField(++s, f); 256 | else 257 | *f = 0; 258 | 259 | if(UxPad(f, fcx + 10, 3)) 260 | return -1; 261 | } 262 | 263 | return *s || !fcx[2] ? -1 : 0; 264 | } 265 | 266 | // unsigned int UxGetDrvUsr(char *s) : get drive + user specification, or -1 on error. 267 | 268 | UxGetDrvUsr(s) 269 | char *s; 270 | { 271 | int drv, usr; 272 | 273 | #ifdef CC_FCX_DIR 274 | char *du; 275 | 276 | if((du = DirToDrvUsr(s))) 277 | s = du; 278 | #endif 279 | 280 | drv = usr = 0xDD; 281 | 282 | if(*s >= 'A' && *s <= 'P') 283 | drv = *s++ -'A'; 284 | 285 | if(isdigit(*s)) 286 | { 287 | usr = 0; 288 | 289 | do 290 | { 291 | if((usr = usr * 10 + *s - '0') > 15) 292 | break; 293 | } while(isdigit(*++s)); 294 | } 295 | 296 | if(*s) 297 | return -1; 298 | 299 | return (drv << 8) | usr; 300 | } 301 | 302 | // int UxPad(char *s, char *d, int n) : pad field with spaces -- return 0 on success, else -1. 303 | 304 | UxPad(s, d, n) 305 | char *s, *d; int n; 306 | { 307 | int i; char f; 308 | 309 | f = ' '; 310 | 311 | for(i = 0; i != n; ++i) 312 | { 313 | if(*s == '*') 314 | { 315 | f = '?'; ++s; break; 316 | } 317 | else if(*s) 318 | *d++ = *s++; 319 | else 320 | break; 321 | } 322 | 323 | if(*s) 324 | return -1; 325 | 326 | while(i != n) 327 | { 328 | *d++ = f; ++i; 329 | } 330 | 331 | return 0; 332 | } 333 | 334 | // char *UxField(char *s, char *d) : get field -- return pointer to delimiter, else NULL. 335 | 336 | // Max. length of field is 8. 337 | // Field can be empty (zero length). 338 | // Delimiters: ':', '.', '\0'. 339 | 340 | UxField(s, d) 341 | char *s, *d; 342 | { 343 | char c; int i; 344 | 345 | for(i = 0; i != 8; ++i) 346 | { 347 | c = toupper(*s); 348 | 349 | if(isalpha(c) || isdigit(c) || c == '$' || c == '_' || c == '*' || c == '?') 350 | { 351 | *d++ = c; ++s; 352 | } 353 | else 354 | break; 355 | } 356 | 357 | *d = 0; c = *s; 358 | 359 | if(c == ':' || c == '.' || c == '\0') 360 | return s; 361 | 362 | return NULL; 363 | } 364 | 365 | /************************ 366 | UxFcxIsAmb(fcx) 367 | BYTE *fcx; 368 | { 369 | int i; 370 | 371 | for(i = 0; i < 11; ++i) 372 | { 373 | if(*++fcx == '?') 374 | return 1; 375 | } 376 | 377 | return 0; 378 | } 379 | *******************/ 380 | 381 | // unsigned int UxGetPath(char *path) : get user + drive spec. from path, or -1 on error. 382 | 383 | // UxGetPath("A1:") --> 0x0001 384 | // UxGetPath("root:") --> ? 385 | 386 | UxGetPath(path) 387 | char *path; 388 | { 389 | char s[9]; 390 | 391 | path = UxField(path, s); 392 | 393 | if(*path == ':' && !path[1] && *s) 394 | return UxGetDrvUsr(s); 395 | 396 | return -1; 397 | } 398 | 399 | // unsigned int UxChdir(char *path) : change drive + user from path -- return drive + user, or -1 on error. 400 | 401 | // UxChdir("A1:") --> 0x0001 402 | // UxChdir("root:") --> ? 403 | 404 | UxChdir(path) 405 | char *path; 406 | { 407 | int du, drv, usr; 408 | 409 | if((du = UxGetPath(path)) != -1) 410 | { 411 | drv = (du >> 8) & 0xFF; 412 | usr = du & 0xFF; 413 | 414 | if(drv != 0xDD && drv != bdos_a(BF_GETDRV, 0)) 415 | bdos_hl(BF_SETDRV, drv); 416 | 417 | if(usr != 0xDD && usr != bdos_a(BF_USER, 0xFFFF)) 418 | bdos_hl(BF_USER, usr); 419 | 420 | return du; 421 | } 422 | 423 | return -1; 424 | } 425 | 426 | #else 427 | 428 | /** 429 | * @fn int setfcb(char *fname, char *fcb) 430 | * @brief Make FCB. 431 | * 432 | * This function is available if CC_FCX is not defined. 433 | * 434 | * @param fname - filename 435 | * @param fcb - destination FCB 436 | * @return 0 on success, else != 0 437 | */ 438 | #asm 439 | 440 | setfcb: 441 | POP BC 442 | POP DE 443 | POP HL 444 | PUSH HL ;HL = fname address 445 | PUSH DE ;DE = fcb address 446 | PUSH BC 447 | 448 | INC HL ;Check for optional A: ... P: drive 449 | LD A,(HL) 450 | DEC HL 451 | CP ':' 452 | JR NZ,sfcbdef 453 | LD A,(HL) 454 | CALL sfcbupp 455 | CP 'A' 456 | JR C,sfcberr 457 | CP 'P' + 1 458 | JR NC,sfcberr 459 | SUB 'A' - 1 460 | INC HL 461 | INC HL 462 | JR sfcbdrv 463 | 464 | sfcbdef 465 | XOR A ;Default drive 466 | 467 | sfcbdrv 468 | LD (DE),A ;Set drive in fcb 469 | INC DE 470 | 471 | sfcbnam 472 | LD C,'.' ;Set name in fcb 473 | LD B,8 474 | CALL sfcbtok 475 | LD A,B 476 | CP 8 477 | JR Z,sfcberr 478 | LD A,(HL) 479 | OR A 480 | JR Z,sfcbtyp 481 | CP '.' 482 | JR NZ,sfcberr 483 | INC HL 484 | 485 | sfcbtyp 486 | LD C,0 ;Set type in fcb 487 | LD B,3 488 | CALL sfcbtok 489 | LD A,(HL) 490 | OR A 491 | JR NZ,sfcberr 492 | 493 | LD A,0 ;Fill the rest of the fcb with zeroes 494 | LD B,24 495 | CALL sfcbset 496 | 497 | LD HL,0 ;Success 498 | RET 499 | 500 | ;Error entry for sfcbtok 501 | 502 | sfcbtke 503 | POP HL ;Remove address from stack 504 | 505 | sfcberr 506 | LD HL,1 ;Error 507 | RET 508 | 509 | ;Set field (name or type) 510 | ; 511 | ;In: 512 | ; C = delimiter ('.' for name, 0 for type) 513 | ; B = Max. field length (8 for name, 3 for type) 514 | ; 515 | ;Out: 516 | ; B = Remain length 517 | 518 | sfcbtok 519 | LD A,(HL) ;End of string? 520 | OR A 521 | JR Z,sfcbspc 522 | CP C ;Delimiter? 523 | JR Z,sfcbspc 524 | CP '*' ;Wildcard? 525 | JR Z,sfcbamb 526 | 527 | ;Accept only valid characters 528 | 529 | CP '#' ;# $ % 530 | JR C,sfcbtke 531 | CP '%' + 1 532 | JR C,sfcbtks 533 | CP '0' ;0 ... 9 534 | JR C,sfcbtke 535 | CP '9' + 1 536 | JR C,sfcbtks 537 | CALL sfcbupp ;? @ A ... Z 538 | CP '?' 539 | JR C,sfcbtke 540 | CP 'Z' + 1 541 | JR C,sfcbtks 542 | CP '_' ;_ 543 | JR NZ,sfcbtke 544 | 545 | sfcbtks 546 | LD (DE),A ;Set character in fcb 547 | INC HL 548 | INC DE 549 | DJNZ sfcbtok ;Continue upto max. length 550 | RET 551 | 552 | ;Fill the remain field length with spaces, 553 | ;and return the remain length. 554 | 555 | sfcbspc 556 | LD A,' ' 557 | LD C,B 558 | CALL sfcbset 559 | LD B,C 560 | RET 561 | 562 | ;Fill the remain field length with '?' 563 | ;and set remain length to 0. 564 | 565 | sfcbamb 566 | LD A,'?' 567 | INC HL 568 | 569 | ;Fill memory 570 | ; 571 | ;In: 572 | ; DE = address 573 | ; B = length 574 | ; A = value 575 | 576 | sfcbset 577 | LD (DE),A 578 | INC DE 579 | DJNZ sfcbset 580 | RET 581 | 582 | ;Convert character to uppercase 583 | ; 584 | ;In: 585 | ; A = Character 586 | ; 587 | ;Out: 588 | ; A = Character converted to uppercase if it was: a ... z 589 | 590 | sfcbupp 591 | CP 'a' 592 | RET C 593 | CP 'z' + 1 594 | RET NC 595 | SUB 32 596 | RET 597 | 598 | #endasm 599 | 600 | #endif 601 | 602 | #endif 603 | 604 |  -------------------------------------------------------------------------------- /cpm_player.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/cpm_player.exe -------------------------------------------------------------------------------- /ctype.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ctype.h 3 | * @brief Character tests and conversion functions. 4 | * @author Miguel I. Garcia Lopez / FloppySoftware 5 | * 6 | * Character tests and conversion functions, for MESCC (Mike's Enhanced 7 | * Small C Compiler for Z80 & CP/M). 8 | * 9 | * Revisions: 10 | * - 19 Dec 2000 : Last revision. 11 | * - 16 Apr 2007 : GPL'd. 12 | * - 15 Aug 2016 : Documented. GPL v3. 13 | * 14 | * Copyright (c) 1999-2016 Miguel I. Garcia Lopez / FloppySoftware. 15 | * 16 | * Licensed under the GNU General Public License v3. 17 | * 18 | * http://www.floppysoftware.es 19 | * floppysoftware@gmail.com 20 | */ 21 | #ifndef CTYPE_H 22 | 23 | #define CTYPE_H 24 | 25 | /** 26 | * @fn int isalpha(char ch) 27 | * @brief Test if ch is a letter. 28 | * @param ch - character to test 29 | * @return true or false 30 | */ 31 | #asm 32 | 33 | isalpha 34 | ld a,l 35 | ld hl,0 36 | cp 'A' 37 | ret c 38 | cp 'Z'+1 39 | jr c,isalpha1 40 | cp 'a' 41 | ret c 42 | cp 'z'+1 43 | ret nc 44 | isalpha1 45 | inc l 46 | ret 47 | 48 | #endasm 49 | 50 | /** 51 | * @fn int isdigit(char ch) 52 | * @brief Test if ch is a decimal digit. 53 | * @param ch - character to test 54 | * @return true or false 55 | */ 56 | #asm 57 | 58 | isdigit 59 | ld a,l 60 | ld hl,0 61 | cp '0' 62 | ret c 63 | cp '9'+1 64 | ret nc 65 | inc l 66 | ret 67 | 68 | #endasm 69 | 70 | /** 71 | * @fn int isxdigit(char ch) 72 | * @brief Test if ch is an hexadecimal digit. 73 | * @param ch - character to test 74 | * @return true or false 75 | */ 76 | #asm 77 | 78 | isxdigit 79 | LD C,L 80 | CALL isdigit 81 | RET C 82 | LD HL,0 83 | LD A,C 84 | CP 'A' 85 | RET C 86 | CP 'G' 87 | JR C,isxdigit1 88 | CP 'a' 89 | RET C 90 | CP 'g' 91 | RET NC 92 | isxdigit1 93 | INC L 94 | RET 95 | 96 | #endasm 97 | 98 | /** 99 | * @fn int isalnum(char ch) 100 | * @brief Test if ch is a letter or a decimal digit. 101 | * @param ch - character to test 102 | * @return true or false 103 | */ 104 | #asm 105 | 106 | isalnum 107 | LD C,L 108 | CALL isdigit 109 | RET C 110 | LD L,C 111 | JP isalpha 112 | 113 | #endasm 114 | 115 | /** 116 | * @fn int isupper(char ch) 117 | * @brief Test if ch is a letter in uppercase. 118 | * @param ch - character to test 119 | * @return true or false 120 | */ 121 | #asm 122 | 123 | isupper 124 | ld a,l 125 | ld hl,0 126 | cp 'A' 127 | ret c 128 | cp 'Z'+1 129 | ret nc 130 | inc l 131 | ret 132 | 133 | #endasm 134 | 135 | /** 136 | * @fn int islower(char ch) 137 | * @brief Test if ch is a letter in lowercase. 138 | * @param ch - character to test 139 | * @return true or false 140 | */ 141 | #asm 142 | 143 | islower 144 | ld a,l 145 | ld hl,0 146 | cp 'a' 147 | ret c 148 | cp 'z'+1 149 | ret nc 150 | inc l 151 | ret 152 | 153 | #endasm 154 | 155 | /** 156 | * @fn int toupper(char ch) 157 | * @brief Convert letter to uppercase. 158 | * 159 | * If ch is not a letter in lowercase, returns ch unchanged. 160 | * 161 | * @param ch - character to convert 162 | * @return ch in uppercase 163 | */ 164 | #asm 165 | 166 | toupper 167 | ld a,l 168 | cp 'a' 169 | ret c 170 | cp 'z'+1 171 | ret nc 172 | sub 20h 173 | ld l,a 174 | ret 175 | 176 | #endasm 177 | 178 | /** 179 | * @fn int tolower(char ch) 180 | * @brief Convert letter to lowercase. 181 | * 182 | * If ch is not a letter in uppercase, returns ch unchanged. 183 | * 184 | * @param ch - character to convert 185 | * @return ch in lowercase 186 | */ 187 | #asm 188 | 189 | tolower 190 | ld a,l 191 | cp 'A' 192 | ret c 193 | cp 'Z'+1 194 | ret nc 195 | add 20h 196 | ld l,a 197 | ret 198 | 199 | #endasm 200 | 201 | #endif 202 | 203 |  -------------------------------------------------------------------------------- /fprintf.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file fprintf.h 3 | * @brief Library for fprintf() function. 4 | * @author Miguel I. Garcia Lopez / FloppySoftware 5 | * 6 | * Implementation of fprintf() function, for MESCC (Mike's Enhanced 7 | * Small C Compiler for Z80 & CP/M). 8 | * 9 | * Revisions: 10 | * - 23 Jan 2001 : Last revision. 11 | * - 16 Apr 2007 : GPL'd. 12 | * - 25 Aug 2016 : Documented. GPL v3. 13 | * 14 | * Copyright (c) 1999-2016 Miguel I. Garcia Lopez / FloppySoftware. 15 | * 16 | * Licensed under the GNU General Public License v3. 17 | * 18 | * http://www.floppysoftware.es 19 | * floppysoftware@gmail.com 20 | */ 21 | #ifndef FPRINTF_H 22 | 23 | #define FPRINTF_H 24 | 25 | // Dependencies 26 | // ------------ 27 | 28 | #ifndef XPRINTF_H 29 | #include 30 | #endif 31 | 32 | #ifndef FILEIO_H 33 | #include 34 | #endif 35 | 36 | /** 37 | * @fn int fprintf(FILE *fp, char *fmt, arg1, arg2, ...) 38 | * @brief Formatted output to a file. 39 | * 40 | * See the documentation for xprintf.h to learn about the string format. 41 | * 42 | * @param fp - file pointer 43 | * @param fmt - string format 44 | * @param arg1 - argument #1 45 | * @param arg? - argument #? 46 | * @return number or characters written, or -1 on failure. 47 | */ 48 | #asm 49 | 50 | fprintf: 51 | ADD HL,HL 52 | ADD HL,SP ;HL=Adr. fmt 53 | 54 | LD DE,xfpfout 55 | PUSH DE 56 | LD DE,xfpfend 57 | PUSH DE 58 | PUSH HL 59 | 60 | INC HL 61 | INC HL ;HL=Adr. *fp 62 | LD A,(HL) 63 | INC HL 64 | LD H,(HL) 65 | LD L,A 66 | LD (xfpfout+2),HL 67 | 68 | CALL xprintf 69 | 70 | POP BC 71 | POP BC 72 | POP BC 73 | 74 | RET 75 | #endasm 76 | 77 | // int xfpfout(char ch) : output ch to a file; return 0 on success, !=0 on failure. 78 | 79 | #asm 80 | 81 | xfpfout: 82 | PUSH HL ;Char. 83 | LD HL,0 ;*FP 84 | PUSH HL 85 | 86 | CALL fputc 87 | 88 | POP BC 89 | POP BC 90 | 91 | EX DE,HL 92 | LD HL,0 93 | 94 | LD A,255 95 | CP D 96 | RET NZ 97 | CP E 98 | RET NZ 99 | 100 | INC L 101 | RET 102 | #endasm 103 | 104 | // void xfpfend(void) : end formatted output; currently does nothing. 105 | 106 | #asm 107 | 108 | xfpfend: 109 | RET 110 | 111 | #endasm 112 | 113 | #endif 114 | 115 |  -------------------------------------------------------------------------------- /hello.c: -------------------------------------------------------------------------------- 1 | /* hello.c 2 | 3 | Hello world for MESCC. 4 | 5 | Copyright (c) 2015 Miguel I. Garcia Lopez. 6 | 7 | This program is free software; you can redistribute it and/or modify it 8 | under the terms of the GNU General Public License as published by the 9 | Free Software Foundation; either version 2, or (at your option) any 10 | later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 20 | 21 | Compile with: 22 | 23 | cc hello 24 | ccopt hello 25 | zsm hello 26 | hextocom hello 27 | 28 | 23 Feb 2015 29 | */ 30 | 31 | #include "mescc.h" 32 | #include "conio.h" 33 | 34 | main() 35 | { 36 | puts("Hello world!"); 37 | } 38 | 39 | -------------------------------------------------------------------------------- /hextocom.c: -------------------------------------------------------------------------------- 1 | /* hextocom.c 2 | 3 | Converts an HEX file into a COM file for CP/M. 4 | 5 | (C) 2007-2016 FloppySoftware (Miguel I. Garcia Lopez, Spain). 6 | 7 | This program is free software; you can redistribute it and/or modify it 8 | under the terms of the GNU General Public License as published by the 9 | Free Software Foundation; either version 2 of the License, or (at your 10 | option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, but 13 | WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 | 21 | To compile with MESCC: 22 | 23 | cc hextocom 24 | ccopt hextocom.zsm 25 | zsm hextocom 26 | hextocom hextocom 27 | 28 | Revisions: 29 | 30 | (hextobin.c) 31 | 32 | 18 Apr 2007 : v1.00 : 33 | 21 Apr 2007 : : Shows first and last addresses, code size. 34 | 29 Apr 2007 : v1.01 : Bug showing code size upper than 0x8000 (shows 35 | negative number). Changed %d to %u to solve this bug. 36 | 15 May 2007 : v1.02 : Change usage text. 37 | 38 | (hextocom.c) 39 | 40 | 13 Nov 2014 : v1.03 : Modified to generate COM files for CP/M. 41 | 04 Sep 2015 : v1.04 : Modified some comments and messages. 42 | 10 Jan 2016 : v1.05 : Cleaned. 43 | */ 44 | 45 | /* Defines for MESCC libraries 46 | --------------------------- 47 | */ 48 | #define CC_FILEIO_SMALL // Exclude fread(), fwrite() and fgets(). 49 | 50 | /* Standard MESCC library 51 | ---------------------- 52 | */ 53 | #include 54 | 55 | /* Standard MESCC libraries 56 | ------------------------ 57 | */ 58 | #include 59 | #include 60 | #include 61 | 62 | /* Project defs. 63 | ------------- 64 | */ 65 | #define APP_NAME "HexToCom" 66 | #define APP_VERSION "v1.05 / 10 Jan 2016" 67 | #define APP_COPYRGT "(c) 2007-2016 FloppySoftware" 68 | #define APP_USAGE "HexToCom filename" 69 | 70 | /* Globals 71 | ------- 72 | */ 73 | FILE *fpi, /* HEX - Input file */ 74 | *fpo; /* COM - Output file */ 75 | 76 | BYTE chksum; /* Checksum of current line */ 77 | 78 | WORD adr, /* Load address */ 79 | ladr, /* Load address of current line */ 80 | first_adr; /* First address */ 81 | 82 | int lbytes, /* Number of data bytes of current line */ 83 | line, /* Number of current line */ 84 | run, /* Zero to exit program */ 85 | flag_adr; /* Zero if load address undefined */ 86 | 87 | char fn_hex[FILENAME_MAX], /* HEX - filename */ 88 | fn_com[FILENAME_MAX]; /* COM - filename */ 89 | 90 | /* Print error and exit 91 | -------------------- 92 | */ 93 | error(txt) 94 | char *txt; 95 | { 96 | printf("%s: %s.\n", APP_NAME, txt); 97 | exit(-1); 98 | } 99 | 100 | /* Print error with line number and exit 101 | ------------------------------------- 102 | */ 103 | errorln(txt) 104 | char *txt; 105 | { 106 | printf("%s: Error in line %d - %s.\n", APP_NAME, line, txt); 107 | exit(-1); 108 | } 109 | 110 | /* Read hex nibble 111 | --------------- 112 | */ 113 | BYTE getnib() 114 | { 115 | int c; 116 | 117 | c=fgetc(fpi); 118 | 119 | if(c>='0' && c<='9') 120 | return c-'0'; 121 | 122 | if(c>='A' && c<='F') 123 | return c-'A'+10; 124 | 125 | if(c==EOF) 126 | error("Unexpected EOF"); 127 | 128 | error("Bad hexadecimal digit"); 129 | } 130 | 131 | /* Read two hex nibbles 132 | -------------------- 133 | */ 134 | BYTE gethex() 135 | { 136 | BYTE nib, hex; 137 | 138 | nib=getnib(); 139 | 140 | chksum+=(hex=(nib << 4) + getnib()); 141 | 142 | return hex; 143 | } 144 | 145 | /* Write byte 146 | ---------- 147 | */ 148 | putbyte(byte) 149 | BYTE byte; 150 | { 151 | if(fputc(byte, fpo)==EOF) 152 | error("Writing COM file"); 153 | } 154 | 155 | /* Main 156 | ---- 157 | */ 158 | main(argc, argv) 159 | int argc, argv[]; 160 | { 161 | /* Program name, copyright, etc. */ 162 | 163 | printf("%s %s\n\n", APP_NAME, APP_VERSION); 164 | printf("%s\n\n", APP_COPYRGT); 165 | 166 | /* Show usage? */ 167 | 168 | if(argc != 2) 169 | { 170 | printf("Usage: %s\n", APP_USAGE); 171 | exit(0); 172 | } 173 | 174 | /* Filenames */ 175 | 176 | if(strchr(argv[1], '.') != NULL) 177 | error("Bad filename (no type, please)"); 178 | 179 | if(strlen(argv[1]) > 10) /* D:FILENAME */ 180 | error("Bad filename (too long)"); 181 | 182 | strcat(strcpy(fn_hex, argv[1]), ".HEX"); 183 | strcat(strcpy(fn_com, argv[1]), ".COM"); 184 | 185 | /* Open files */ 186 | 187 | if((fpi=fopen(fn_hex, "r"))==NULL) 188 | error("Opening HEX file"); 189 | 190 | if((fpo=fopen(fn_com, "wb"))==NULL) 191 | error("Opening COM file"); 192 | 193 | /* Start process */ 194 | 195 | first_adr=adr=0; /* Load address */ 196 | line=run=1; /* Line number and loop variable */ 197 | flag_adr=0; /* Load address undefined */ 198 | 199 | while(run) 200 | { 201 | if(fgetc(fpi) != ':') 202 | errorln("Missing colon"); 203 | 204 | chksum=0; 205 | 206 | lbytes=gethex(); /* Bytes per line */ 207 | 208 | ladr=gethex(); 209 | ladr=(ladr<<8)+gethex(); /* Load adress */ 210 | 211 | switch(gethex()) /* Line type */ 212 | { 213 | case 0 : /* Data */ 214 | if(!lbytes) 215 | { 216 | run = 0; 217 | break; 218 | } 219 | 220 | if(!flag_adr) 221 | { 222 | if((first_adr=adr=ladr) != 0x0100) 223 | error("Start address must be 0100H"); 224 | 225 | ++flag_adr; 226 | } 227 | else if(adrladr) 236 | errorln("Bad address"); 237 | 238 | adr+=lbytes; 239 | 240 | while(lbytes--) 241 | putbyte(gethex()); 242 | break; 243 | case 1 : /* End */ 244 | run=0; 245 | break; 246 | default : 247 | errorln("Unknown record type"); 248 | break; 249 | } 250 | 251 | gethex(); /* Checksum */ 252 | 253 | if(chksum) 254 | errorln("Bad checksum"); 255 | 256 | if(fgetc(fpi)!='\n') 257 | errorln("Missing newline"); 258 | 259 | ++line; 260 | } 261 | 262 | /* Close files */ 263 | 264 | if(fclose(fpi)) 265 | error("Closing HEX file"); 266 | 267 | if(fclose(fpo)) 268 | error("Closing COM file"); 269 | 270 | /* Print facts */ 271 | 272 | printf("First address: %04x\n", first_adr); 273 | printf("Last address: %04x\n", adr-1); 274 | printf("Size of code: %04x (%u dec) bytes\n", adr-first_adr, adr-first_adr); 275 | 276 | } 277 | -------------------------------------------------------------------------------- /make_cc.c: -------------------------------------------------------------------------------- 1 | /* make_cc.c 2 | 3 | Mike's Enhanced Small C Compiler for Z80 & CP/M 4 | 5 | Build the compiler itself with MESCC under a z80 & CP/M environment. 6 | 7 | Copyright (c) 1999-2016 Miguel I. Garcia Lopez, FloppySoftware. 8 | 9 | This program is free software; you can redistribute it and/or modify it 10 | under the terms of the GNU General Public License as published by the 11 | Free Software Foundation; either version 2, or (at your option) any 12 | later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program; if not, write to the Free Software 21 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 22 | 23 | How to build MESCC with this file: 24 | 25 | cc make_cc -s:1024 26 | ccopt make_cc 27 | zsm make_cc 28 | hextocom make_cc 29 | 30 | Now MAKE_CC.COM is the new version of the compiler. 31 | 32 | Revisions: 33 | 34 | 16 Jan 2001 : Last revision. 35 | 16 Apr 2007 : GPL'd. 36 | 04 Sep 2015 : Modified some comments. 37 | 26 Oct 2015 : Added c_defs.c. Modified some comments. 38 | 10 Jan 2015 : Added CC_FILEIO_SMALL def. 39 | 19 Jul 2016 : Removed CC_FILEIO_SMALL def. 40 | 11 Oct 2016 : Added c_parser.c. Documented. 41 | 20 Oct 2016 : Added c_string.c. 42 | */ 43 | 44 | // MESCC #definitions 45 | // ------------------ 46 | 47 | // Nothing yet... 48 | 49 | // MESCC runtime 50 | // ------------- 51 | 52 | #include 53 | 54 | // MESCC libraries 55 | // --------------- 56 | 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | 63 | // Compiler modules 64 | // ---------------- 65 | 66 | #include "c_defs.c" 67 | #include "c_string.c" 68 | #include "c_main.c" 69 | #include "c_parser.c" 70 | #include "c_cpp.c" 71 | #include "c_expr.c" 72 | #include "c_asm.c" 73 | #include "c_error.c" 74 | #include "c_buf.c" 75 | #include "c_iocon.c" 76 | #include "c_iofile.c" 77 |  -------------------------------------------------------------------------------- /mem.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file mem.h 3 | * @brief Memory functions. 4 | * @author Miguel I. Garcia Lopez / FloppySoftware 5 | * 6 | * Memory functions, for MESCC (Mike's Enhanced 7 | * Small C Compiler for Z80 & CP/M). 8 | * 9 | * Revisions: 10 | * - 25 Oct 2000 : Last revision. 11 | * - 16 Apr 2007 : GPL'd. 12 | * - 25 Aug 2016 : Documented. GPL v3. 13 | * - 25 Dec 2018 : Optimize memset() for speed. 14 | * 15 | * Copyright (c) 1999-2018 Miguel I. Garcia Lopez / FloppySoftware. 16 | * 17 | * Licensed under the GNU General Public License v3. 18 | * 19 | * http://www.floppysoftware.es 20 | * floppysoftware@gmail.com 21 | */ 22 | #ifndef MEM_H 23 | 24 | #define MEM_H 25 | 26 | /** 27 | * @fn char *memset(char *dst, char data, int count) 28 | * @brief Fill 'count' bytes with 'data' into 'dst'. 29 | * @param dst - destination 30 | * @param data - fill byte 31 | * @param count - how many 32 | * @return pointer to 'dst' 33 | */ 34 | #asm 35 | 36 | memset: 37 | POP AF 38 | POP BC 39 | POP DE 40 | POP HL 41 | PUSH HL 42 | PUSH DE 43 | PUSH BC 44 | PUSH AF 45 | 46 | LD A,B 47 | OR C 48 | RET Z 49 | 50 | PUSH HL 51 | 52 | LD (HL),E 53 | LD D,H 54 | LD E,L 55 | INC DE 56 | DEC BC 57 | LDIR 58 | 59 | POP HL 60 | RET 61 | #endasm 62 | 63 | /** 64 | * @fn char *memcpy(char *dst, char *src, int count) 65 | * @brief Copy 'count' bytes from 'src' to 'dst'. 66 | * @param dst - destination 67 | * @param src - source 68 | * @param count - how many 69 | * @return pointer to 'dst' 70 | */ 71 | #asm 72 | 73 | memcpy: 74 | POP AF 75 | POP BC 76 | POP HL 77 | POP DE 78 | PUSH DE 79 | PUSH HL 80 | PUSH BC 81 | PUSH AF 82 | PUSH DE 83 | LD A,B 84 | OR C 85 | JR Z,memcpy2 86 | LDIR 87 | memcpy2 88 | POP HL 89 | RET 90 | #endasm 91 | 92 | /** 93 | * @fn int memcmp(char *mem1, char *mem2, int count) 94 | * @brief Compare 'count' bytes. 95 | * @param mem1 - pointer 96 | * @param mem2 - pointer 97 | * @param count - how many 98 | * @return <0 on mem1 < mem2; =0 on mem1 == mem2; >0 on mem1 > mem2 99 | */ 100 | #asm 101 | 102 | memcmp 103 | POP AF 104 | POP BC 105 | POP HL 106 | POP DE 107 | PUSH DE 108 | PUSH HL 109 | PUSH BC 110 | PUSH AF 111 | 112 | memcmp1 113 | LD A,C 114 | OR B 115 | JR Z,memcmp2 116 | 117 | DEC BC 118 | 119 | LD A,(DE) 120 | CP (HL) 121 | INC DE 122 | INC HL 123 | JR Z,memcmp1 124 | 125 | memcmp2 126 | LD HL,0 127 | RET Z 128 | JR NC,memcmp3 129 | DEC HL 130 | RET 131 | 132 | memcmp3 133 | INC L 134 | RET 135 | #endasm 136 | 137 | #endif 138 | 139 |  -------------------------------------------------------------------------------- /printf.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file printf.h 3 | * @brief Library for printf() function. 4 | * @author Miguel I. Garcia Lopez / FloppySoftware 5 | * 6 | * Implementation of printf() function, for MESCC (Mike's Enhanced 7 | * Small C Compiler for Z80 & CP/M). 8 | * 9 | * Revisions: 10 | * - 20 Oct 2000 : Last revision. 11 | * - 16 Apr 2007 : GPL'd. 12 | * - 25 Aug 2016 : Documented. GPL v3. 13 | * 14 | * Copyright (c) 1999-2016 Miguel I. Garcia Lopez / FloppySoftware. 15 | * 16 | * Licensed under the GNU General Public License v3. 17 | * 18 | * http://www.floppysoftware.es 19 | * floppysoftware@gmail.com 20 | */ 21 | #ifndef PRINTF_H 22 | 23 | #define PRINTF_H 24 | 25 | // Dependencies 26 | // ------------ 27 | 28 | #ifndef XPRINTF_H 29 | #include 30 | #endif 31 | 32 | #ifndef CONIO_H 33 | #include 34 | #endif 35 | 36 | /** 37 | * @fn int printf(char *fmt, arg1, arg2, ...) 38 | * @brief Formatted output to stdout (or console). 39 | * 40 | * See the documentation for xprintf.h to learn about the string format. 41 | * 42 | * @param fmt - string format 43 | * @param arg1 - argument #1 44 | * @param arg? - argument #? 45 | * @return number or characters written, or -1 on failure (currently always #). 46 | */ 47 | #asm 48 | 49 | printf: 50 | ADD HL,HL 51 | ADD HL,SP 52 | INC HL 53 | INC HL ;HL=Adr. fmt 54 | 55 | LD DE,xpfout 56 | PUSH DE 57 | LD DE,xpfend 58 | PUSH DE 59 | PUSH HL 60 | 61 | CALL xprintf 62 | 63 | POP BC 64 | POP BC 65 | POP BC 66 | 67 | RET 68 | #endasm 69 | 70 | // int xpfout(char ch) : output ch to stdout; return 0 on success, !=0 on failure (currently always returns 0). 71 | 72 | #asm 73 | 74 | xpfout: 75 | PUSH HL 76 | CALL putchar 77 | POP BC 78 | LD HL,0 79 | RET 80 | 81 | #endasm 82 | 83 | // void xpfend(void) : end formatted output; currently does nothing. 84 | 85 | #asm 86 | 87 | xpfend: 88 | RET 89 | 90 | #endasm 91 | 92 | #endif 93 | 94 |  -------------------------------------------------------------------------------- /qsort.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file qsort.h 3 | * @brief Sort function. 4 | * @author Miguel I. Garcia Lopez / FloppySoftware 5 | * 6 | * This library implements a sort function of general use, 7 | * which uses the bubble sort algorithm, for MESCC (Mike's Enhanced 8 | * Small C Compiler for Z80 & CP/M). 9 | * 10 | * Revisions: 11 | * - 30 Nov 2015 : First version (bubble sort). 12 | * - 15 Aug 2016 : Documented. GPL v3. 13 | * 14 | * Copyright (c) 2015-2016 Miguel I. Garcia Lopez / FloppySoftware. 15 | * 16 | * Licensed under the GNU General Public License v3. 17 | * 18 | * http://www.floppysoftware.es 19 | * floppysoftware@gmail.com 20 | */ 21 | #ifndef QSORT_H 22 | 23 | #define QSORT_H 24 | 25 | /** 26 | * @fn void qsort(void *base, size_t items, size_t size, int (*comp)(const void *, const void*)) 27 | * @brief Sort an array of elements. 28 | * 29 | * Sort an array of elements into ascending order. 30 | * 31 | * The comparison function must return: 32 | * - <0 on elem1 < elem2 33 | * - =0 on elem1 == elem2 34 | * - >0 on elem1 > elem2 35 | * 36 | * @param base - address of first element 37 | * @param items - number of elements in the array 38 | * @param size - size in bytes of each element 39 | * @param comp - comparison function 40 | */ 41 | qsort(base, items, size, comp) 42 | BYTE *base; int items, size; WORD comp; 43 | { 44 | int i, j, k; 45 | BYTE *pi, *pj, t; 46 | 47 | for(i = 0; i < items; ++i) 48 | { 49 | for(j = i + 1; j < items; ++j) 50 | { 51 | pi = base + i * size; 52 | pj = base + j * size; 53 | 54 | if(comp(pi, pj) > 0) 55 | { 56 | for(k = 0; k < size; ++k) { 57 | t = *pi; 58 | *pi++ = *pj; 59 | *pj++ = t; 60 | } 61 | } 62 | } 63 | } 64 | } 65 | 66 | #endif 67 | 68 |  -------------------------------------------------------------------------------- /rand.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file rand.h 3 | * @brief Pseudo-random number generation. 4 | * @author Miguel I. Garcia Lopez / FloppySoftware 5 | * 6 | * Pseudo-random number generation, for MESCC (Mike's Enhanced 7 | * Small C Compiler for Z80 & CP/M). 8 | * 9 | * Revisions: 10 | * - 18 Mar 2015 : 1st version. 11 | * - 23 Mar 2015 : Trying to improve rand(). 12 | * - 15 Aug 2016 : Documented. GPL v3. 13 | * 14 | * Defined macros: 15 | * - RAND_MAX 16 | * 17 | * Copyright (c) 2015-2016 Miguel I. Garcia Lopez / FloppySoftware. 18 | * 19 | * Licensed under the GNU General Public License v3. 20 | * 21 | * http://www.floppysoftware.es 22 | * floppysoftware@gmail.com 23 | */ 24 | #ifndef RAND_H 25 | 26 | #define RAND_H 27 | 28 | #define RAND_MAX 32767 29 | 30 | int xs_seed = 1; // Initial value for seed 31 | 32 | /** 33 | * @fn int rand(void) 34 | * @brief Generate a pseudo-random value between 0 and RAND_MAX (both included). 35 | * @return value 36 | */ 37 | rand() 38 | { 39 | // return (xs_seed = ((xs_seed * 3) + 1) & 0x7FFF); 40 | 41 | return (xs_seed = (((xs_seed << 1) + xs_seed) + 1) & 0x7FFF); 42 | } 43 | 44 | /** 45 | * @fn void srand(unsigned int seed) 46 | * @brief Seeds the pseudo-random number generator used by rand(). 47 | * @param seed - value 48 | */ 49 | srand(seed) 50 | unsigned int seed; 51 | { 52 | xs_seed = seed; 53 | } 54 | 55 | #endif 56 | 57 |  -------------------------------------------------------------------------------- /redir.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file redir.h 3 | * @brief I/O redirection in command line. 4 | * @author Miguel I. Garcia Lopez / FloppySoftware 5 | * 6 | * Support library for I/O redirection in command line, 7 | * for MESCC (Mike's Enhanced Small C Compiler for Z80 & CP/M). 8 | * 9 | * Supported redirections: 10 | * - echo < address.txt 11 | * - echo 'Park Avenue, 234b' > address.txt 12 | * - echo 'Call Elvis' >> todo.txt 13 | * 14 | * Revisions: 15 | * - 08 Dec 2014 : 1st version. 16 | * - 29 Nov 2016 : Support for '>>' redirection. Optimizations in NULL comparisons. 17 | * - 07 Dec 2016 : GPL v3. 18 | * 19 | * Copyright (c) 2014-2016 Miguel I. Garcia Lopez / FloppySoftware. 20 | * 21 | * Licensed under the GNU General Public License v3. 22 | * 23 | * http://www.floppysoftware.es 24 | * floppysoftware@gmail.com 25 | */ 26 | #ifndef REDIR_H 27 | 28 | #define REDIR_H 29 | 30 | /** 31 | * @fn int redir(int argc, char *argv[]) 32 | * @brief Stdin & stdout redirection in command line. 33 | * @param argc - number of arguments 34 | * @param argv - array of arguments 35 | * @return number of arguments after redirection parsing 36 | */ 37 | redir(argc, argv) 38 | int argc, argv[]; 39 | { 40 | int i, z; char *p; 41 | char *fnin, *fnout; 42 | FILE *fp; 43 | 44 | #ifdef CC_FOPEN_A 45 | int append; 46 | #endif 47 | 48 | fnin = fnout = NULL; 49 | 50 | for(i = 1; i < argc; ++i) 51 | { 52 | p = argv[i]; 53 | 54 | #ifdef CC_FOPEN_A 55 | if(((*p == '<' || *p == '>') && !(p[1])) || (*p == '>' && p[1] == '>' && !(p[2]))) 56 | #else 57 | if((*p == '<' || *p == '>') && !(p[1])) 58 | #endif 59 | { 60 | if(i + 1 == argc) 61 | return -1; /* No filename */ 62 | 63 | if(*p == '<') 64 | fnin = argv[i + 1]; 65 | else 66 | { 67 | fnout = argv[i + 1]; 68 | 69 | #ifdef CC_FOPEN_A 70 | append = p[1]; 71 | #endif 72 | } 73 | 74 | argc -= 2; 75 | 76 | for(z = i; z < argc; ++z) 77 | argv[z] = argv[z + 2]; 78 | --i; 79 | } 80 | } 81 | 82 | if(fnin) 83 | { 84 | if((fp = fopen(fnin, "r"))) 85 | stdin = fp; 86 | else 87 | return -2; 88 | } 89 | 90 | if(fnout) 91 | { 92 | #ifdef CC_FOPEN_A 93 | if((fp = fopen(fnout, (append ? "a" : "w")))) 94 | #else 95 | if((fp = fopen(fnout, "w"))) 96 | #endif 97 | stdout = fp; 98 | else 99 | return -3; 100 | } 101 | 102 | return argc; 103 | } 104 | 105 | #endif 106 | 107 |  -------------------------------------------------------------------------------- /setjmp.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file setjmp.h 3 | * @brief Non-local jumps. 4 | * @author Miguel I. Garcia Lopez / FloppySoftware 5 | * 6 | * Non-local jumps functions, for MESCC (Mike's Enhanced 7 | * Small C Compiler for Z80 & CP/M). 8 | * 9 | * Only one jmp_buf is allowed. 10 | * 11 | * Call to setjmp is performed as - ie: setjmp(env): 12 | * LD HL,(env) 13 | * PUSH HL 14 | * CALL setjmp 15 | * POP BC 16 | * 17 | * Call to longjmp is performed as - ie: longjmp(env, 1): 18 | * 19 | * LD HL,(env) 20 | * PUSH HL 21 | * LD HL,1 22 | * PUSH HL 23 | * CALL longjmp 24 | * POP BC 25 | * POP BC 26 | * 27 | * Defined macros: 28 | * - jmp_buf 29 | * 30 | * Revisions: 31 | * - 21 Ago 2015 : Initial version. 32 | * - 22 Ago 2015 : Changed jmp_buf from char to int. 33 | * - 15 Ago 2016 : Documented. GPL v3. 34 | * 35 | * Copyright (c) 2015-2016 Miguel I. Garcia Lopez / FloppySoftware. 36 | * 37 | * Licensed under the GNU General Public License v3. 38 | * 39 | * http://www.floppysoftware.es 40 | * floppysoftware@gmail.com 41 | */ 42 | #ifndef SETJMP_H 43 | 44 | #define SETJMP_H 45 | 46 | #define jmp_buf int // Just something 47 | 48 | WORD setjmp_rt; // Return address 49 | WORD setjmp_sp; // SP 50 | 51 | /** 52 | * @fn int setjmp (jmp_buf env) 53 | * @brief Save state information for later use of longjmp(). 54 | * @param env - buffer for state data 55 | * @return 0 from direct call, other values from a longjmp call 56 | */ 57 | #asm 58 | setjmp 59 | POP HL 60 | LD (setjmp_rt), HL 61 | LD (setjmp_sp), SP 62 | PUSH HL 63 | LD HL, 0 64 | RET 65 | #endasm 66 | 67 | /** 68 | * @fn void longjmp (jmp_buf env, int rv) 69 | * @brief Resume execution after setjmp(). 70 | * 71 | * This function resumes the execution after setjmp(), restoring 72 | * the previously stored state in env. 73 | * 74 | * @param env - buffer with state data 75 | * @param rv - value to return; must be != 0 76 | * @return rv value 77 | */ 78 | #asm 79 | longjmp 80 | POP BC 81 | POP HL 82 | LD SP,(setjmp_sp) 83 | LD DE,(setjmp_rt) 84 | PUSH DE 85 | RET 86 | #endasm 87 | 88 | #endif 89 | 90 |  -------------------------------------------------------------------------------- /small_c_17/-CATALOG.42-: -------------------------------------------------------------------------------- 1 | UK Users Group Volume 42 2 | 3 | DESCRIPTION: (1) Improved version of Small C 4 | (2) Small C optimiser 5 | 6 | NUMBER SIZE NAME COMMENTS 7 | 8 | -CATALOG.42- CONTENTS OF UK VOL. 42 9 | 42.1 3K AMLOAD.C Convert assembler HEX files to AMSDOS BIN files 10 | 42.2 4K AMLOAD.COM / 11 | 42.3 4K AMS.DOC Documentation for AMLOAD and AMS.LIB 12 | 42.4 9K AMS.LIB Small C library for AMSDOS 13 | 42.5 1K CCO.SUB Submit file for optimised compilation 14 | 42.6 5K CONIO2.LIB Small C libraries 15 | 42.7 6K CRUN2.LIB / 16 | 42.8 5K CRUNLONE.LIB / 17 | 42.9 11K FILE2.LIB / 18 | 42.10 10K FORMAT.LIB / 19 | 42.11 4K MORELIB.LIB / 20 | 42.12 3K NUMIO2.LIB / 21 | 42.13 14K OPT.C Small C optimiser in Small C 22 | 42.14 10K OPT.COM / 23 | 42.15 11K OPT.DOC / 24 | 42.16 2K STRING.LIB Small C library 25 | 42.17 2K USQ.COM File Unsqueezer 26 | 42.18 1K WSCLEAN.C WordStar file clean utility 27 | 42.19 3K WSCLEAN.COM / 28 | 42.20 28K ZSC.COM Small C compiler 29 | 42.21 26K ZSC.DOC / 30 | 42.22 19K ZSC-1.CQ / 31 | 42.23 13K ZSC-2.CQ / 32 | 42.24 13K ZSC-C.LIB / 33 | 42.25 11K ZSM.COM Z80 assembler for use with Small C 34 | 42.26 12K ZSM.DOC / 35 |  -------------------------------------------------------------------------------- /small_c_17/AMLOAD.C: -------------------------------------------------------------------------------- 1 | /* This program converts a HEX file developed under CP/M into an Amsdos 2 | BIN file. See the CPC 464 DD1-1 Firmware specification for details of 3 | the file header used. 4 | */ 5 | #include 6 | #include 7 | #include 8 | int ichan; 9 | /* array for file header and start of machine code buffer 10 | buff MUST be declared last */ 11 | char head[128],buff[1]; 12 | main(argc,argv) 13 | int argc,argv[]; 14 | {char ch,*cptr,*iptr,*optr,fname[20],ifname[16],ofname[16]; 15 | /* Use char pointers for 16 bit unsigned numbers */ 16 | char *start,*finish,*chksum; 17 | int count,loop,ochan; 18 | puts("\nCP/M HEX to AMSDOS BIN loader (J.M.H.Hill Nov 1985)\n\n"); 19 | start=finish=chksum=0; 20 | iptr=ifname; 21 | optr=ofname; 22 | for(count=0;count<69;count++)head[count]=0; 23 | head[18]=2; /* Binary file */ 24 | if(argc!=2) 25 | {puts("Give name of input file: "); 26 | gets(fname); 27 | crlf(); 28 | cptr=fname; 29 | } 30 | else cptr=argv[1]; 31 | /* Analyse file name and generate full names for I/P and O/P */ 32 | while((ch=*cptr)==' ')cptr++; 33 | count=1; 34 | while(ch=*cptr++) 35 | {if(count>8)break; 36 | if(ch==' ')break; 37 | if(ch=='.')break; 38 | if(ch==':')count=0; 39 | *iptr++=*optr++=ch; 40 | if(count!=0) 41 | head[count]=ch; 42 | count++; 43 | } 44 | while(count<=8)head[count++]=' '; 45 | *iptr++ = *optr++ = '.'; 46 | *iptr++ ='H';*iptr++ ='E';*iptr++='X'; 47 | *optr++ =head[9] ='B';*optr++ =head[10] ='I';*optr++ =head[11]='N'; 48 | *iptr=*optr=0; 49 | if((ichan=fopen(ifname,"r"))==0){puts("\nI/P file error\n");exit();} 50 | if((ochan=fopen(ofname,"w"))==0){puts("\nO/P file problem\n");exit();} 51 | /* Files are open. Get HEX file in, and transfer code to buffer */ 52 | while(1) 53 | { 54 | while((ch=getc(ichan))!= ':'); 55 | count=fgethex(2); 56 | if(count==0)break; 57 | cptr=fgethex(4); 58 | if(finish<(cptr+count))finish=cptr+count; 59 | if(start==0)start=cptr; 60 | cptr=cptr-start+&buff[0]; 61 | if(fgethex(2)!=0)break; 62 | for(loop=count;loop>0;loop--) 63 | *cptr++ =fgethex(2); 64 | fgethex(2); /* Throw away checksum */ 65 | } 66 | /* Fill in the rest of the header and save the BIN file */ 67 | istore(start,21); 68 | istore(finish-start,24); 69 | istore(start,26); 70 | istore(finish-start,64); 71 | chksum=0; 72 | for(count=0;count<67;count++)chksum=chksum+(head[count]&0xff); 73 | istore(chksum,67); 74 | for(count=0;count<128;count++) 75 | putc(head[count],ochan); 76 | cptr=&buff[0]; 77 | while(cptr<=(finish-start+&buff[0]))putc(*cptr++,ochan); 78 | fclose(ochan); 79 | } 80 | fgethex(nchs) 81 | int nchs; 82 | {char chin; 83 | int val,loop; 84 | val=0; 85 | for(loop=nchs;loop>0;loop--) 86 | {chin=getc(ichan); 87 | chin=chin-'0'; 88 | if(chin>9)chin=chin-7; 89 | val=16*val+chin; 90 | } 91 | return val; 92 | } 93 | 94 | /* Store an integer in header */ 95 | istore(val,loc) 96 | int val,loc; 97 | {int *ptr; 98 | ptr=head+loc; 99 | *ptr=val; 100 | } 101 | tion with its final code in EP -------------------------------------------------------------------------------- /small_c_17/AMLOAD.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/small_c_17/AMLOAD.COM -------------------------------------------------------------------------------- /small_c_17/AMS.DOC: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/small_c_17/AMS.DOC -------------------------------------------------------------------------------- /small_c_17/AMS.LIB: -------------------------------------------------------------------------------- 1 | /* 2 | The functions below form a rather experimental library for use with 3 | Small C to allow programs to be run under AMSDOS. 4 | 5 | The colour names assigned to the numbers below are my own choice. 6 | They do NOT all correspond with the names given in the CPC464 manual. 7 | */ 8 | #define BLACK 0 9 | #define NAVY 1 10 | #define BLUE 2 11 | #define BROWN 3 12 | #define PURPLE 4 13 | #define RED 6 14 | #define GREEN 9 15 | #define RAF 10 16 | #define MUD 12 17 | #define GREY 13 18 | #define ORANGE 15 19 | #define PINK 16 20 | #define LEAF 18 21 | #define SEA 19 22 | #define SKY 20 23 | #define LIME 21 24 | #define YELLOW 24 25 | #define BUFF 25 26 | #define WHITE 26 27 | #asm 28 | ; Define TRUE and FALSE for general use 29 | TRUE EQU 1 30 | FALSE EQU 0 31 | ; 32 | ; 33 | LD SP,0B000H 34 | ; Set up random number seed 35 | LD A,R 36 | LD (ccRSEED),A 37 | LD A,R 38 | LD (ccRSEED+1),A 39 | CALL main 40 | CALL getchar ; Hold till key is pressed 41 | JP 0 42 | ccRSEED: DEFS 2 ;Seed for rand(n) function 43 | ; 44 | ; Original runtime section 45 | ; Based on runtime routines by R.Cain in DDJ no.48 46 | ; 47 | ; Fetch a single byte from (HL) and sign extend into HL 48 | ccgchar: LD A,(HL) 49 | ; Put A into HL and sign extend through H 50 | ccsxt: LD L,A 51 | RLCA 52 | SBC A,A 53 | LD H,A 54 | RET 55 | ;Fetch a 16 bit integer from (HL) to HL 56 | ccgint: LD A,(HL) 57 | INC HL 58 | LD H,(HL) 59 | LD L,A 60 | RET 61 | ;Move a single byte from HL to (DE) 62 | ccpchar: LD A,L 63 | LD (DE),A 64 | RET 65 | ; Move a 16 bit integer in HL to (DE) 66 | ccpint: LD A,L 67 | LD (DE),A 68 | INC DE 69 | LD A,H 70 | LD (DE),A 71 | RET 72 | ; Inclusive or HL and DE to HL 73 | ccor: LD A,L 74 | OR E 75 | LD L,A 76 | LD A,H 77 | OR D 78 | LD H,A 79 | RET 80 | ; Exclusive or HL and DE into HL 81 | ccxor: LD A,L 82 | XOR E 83 | LD L,A 84 | LD A,H 85 | XOR D 86 | LD H,A 87 | RET 88 | ; And HL and DE into HL 89 | ccand: LD A,L 90 | AND E 91 | LD L,A 92 | LD A,H 93 | AND D 94 | LD H,A 95 | RET 96 | ; Compare routines. HL tested against DE 97 | ; HL set to 1 if condition true or 0 if false. 98 | ; 99 | ;HL=DE? 100 | cceq: CALL cccmp 101 | RET Z 102 | DEC HL 103 | RET 104 | ;HL!=DE? 105 | ccne: CALL cccmp 106 | RET NZ 107 | DEC HL 108 | RET 109 | ;DE>HL? (signed) 110 | ccgt: EX DE,HL 111 | JP cclt 112 | ; DE<=HL? (signed) 113 | ccle: CALL cccmp 114 | RET Z 115 | RET C 116 | DEC HL 117 | RET 118 | ; DE>=HL? (signed) 119 | ccge: CALL cccmp 120 | RET NC 121 | DEC HL 122 | RET 123 | ; DE=HL? (unsigned) 144 | ccuge: CALL ccucmp 145 | RET NC 146 | DEC HL 147 | RET 148 | ; DEHL? (unsigned) 154 | ccugt: EX DE,HL 155 | JP ccult 156 | ; DE<=HL? (unsigned) 157 | ccule: CALL ccucmp 158 | RET Z 159 | RET C 160 | DEC HL 161 | RET 162 | ; Unsigned compare. C set if DE=0)n++;else n--; 442 | *iptr=n1/2; /* Avoid being trapped with even numbers */ 443 | if(n==1) return n1; 444 | if(n1<0)n1=-n1; 445 | return (n1%n); 446 | } 447 | #asm 448 | ; Graphical routines 449 | ; 450 | ; 451 | ; Clear screen to ink_no 0: cls() 452 | cls: JP 0BC14H 453 | ; 454 | ; Clear graphics window: gcls() 455 | gcls: JP 0BBDBH 456 | ; 457 | ; Clear current text window: tcls() 458 | tcls: JP 0BB6CH 459 | ; 460 | ; Select a text stream: stream(no) 461 | stream: LD A,L 462 | JP 0BBB4H 463 | ; 464 | ; Set up text window: window(row1,row2,col1,col2) 465 | window: POP BC 466 | POP HL 467 | LD H,L 468 | POP DE 469 | LD L,E 470 | POP DE 471 | LD A,E 472 | POP DE 473 | LD D,L 474 | LD L,A 475 | PUSH HL ;Junk 476 | PUSH HL 477 | PUSH HL 478 | PUSH HL 479 | PUSH BC ; Ret address 480 | JP 0BB66H 481 | ; 482 | ; Plot a point: plot(x,y) 483 | plot: POP BC 484 | POP HL 485 | POP DE 486 | PUSH DE 487 | PUSH HL 488 | PUSH BC 489 | JP 0BBEAH 490 | ; 491 | ; Continue a line to a point: go_on(x,y) 492 | go_on: POP BC 493 | POP HL ;y 494 | POP DE ;x 495 | PUSH DE 496 | PUSH HL 497 | PUSH BC 498 | JP 0BBF6H 499 | ; 500 | ; Set border to single colour: border(colour) 501 | border: LD B,L ; Assumes single colour 502 | LD C,L 503 | JP 0BC38H 504 | ; 505 | ; Set ink number to a single colour: ink(ink_no,colour) 506 | ink: POP DE 507 | POP BC 508 | POP HL 509 | PUSH HL 510 | PUSH BC 511 | PUSH DE 512 | LD A,L 513 | LD B,C ; Single colour 514 | JP 0BC32H 515 | ; 516 | ; Set ink number to two alternating colours: twink(ink_no,col1,col2) 517 | twink: POP DE 518 | POP BC ;col2 519 | POP HL ;col1 520 | LD B,L 521 | POP HL 522 | LD A,L ;ink_no 523 | PUSH HL 524 | PUSH HL ;junk 525 | PUSH BC 526 | PUSH DE 527 | JP 0BC32H 528 | ; 529 | ; Set mode: mode(mode_no) 530 | mode: LD A,L 531 | JP 0BC0EH 532 | ; 533 | ; Set text paper: paper(ink_no) 534 | paper: LD A,L 535 | JP 0BB96H ;Text paper 536 | ; 537 | ; Set graphics background: gpaper(ink_no) 538 | gpaper: LD A,L 539 | JP 0BBE4H ;Graphics background 540 | ; 541 | ; Choose pen for text and graphics: pen(pen_no) 542 | pen: PUSH HL 543 | LD A,L 544 | CALL 0BB90H 545 | POP HL 546 | LD A,L 547 | JP 0BBDEH 548 | ; 549 | ; Cursor on: curon() 550 | curon: JP 0BB8AH 551 | ; 552 | ; Cursor off: curoff() 553 | curoff: JP 0BB8DH 554 | ; 555 | ; Locate text cursor: locate(row,col) 556 | locate: POP BC 557 | POP DE 558 | POP HL 559 | PUSH HL 560 | PUSH DE 561 | PUSH BC 562 | LD H,E 563 | JP 0BB75H 564 | ; 565 | ; Set transparent text mode: transp() 566 | transp: LD A,1 567 | JP 0BB9FH 568 | ; 569 | ; Set opaque text mode: opaque() 570 | opaque: XOR A 571 | JP 0BB9FH 572 | #endasm 573 | 574 | /* Join points with a line. Any number of points. 575 | join(x1,y1,x2,y2, .....xn,yn,npoints) npoints=no of pairs of x,y vals 576 | */ 577 | join(npoints) 578 | int npoints; 579 | { 580 | int *iptr,nvals; 581 | iptr=&npoints; 582 | nvals=2*npoints; 583 | while(nvals--)iptr++; /* Find 1st argument */ 584 | plot(*iptr--,*iptr--);npoints--; 585 | while(npoints--)go_on(*iptr--,*iptr--); 586 | } 587 | ZZZZZZZZZZZZZZZZZZZZZZZ -------------------------------------------------------------------------------- /small_c_17/CCO.SUB: -------------------------------------------------------------------------------- 1 | era m:$1.com 2 | era m:$1.zsm 3 | pip m:=$1.c 4 | zsmall 5 | FILE: AMLOAD .C CRC = DE E9 3 | --> FILE: AMLOAD .COM CRC = 34 35 4 | --> FILE: AMS .DOC CRC = D5 BE 5 | --> FILE: AMS .LIB CRC = D7 9C 6 | --> FILE: CONIO2 .LIB CRC = AD 5B 7 | --> FILE: CRUNLONE.LIB CRC = B4 73 8 | --> FILE: CRUN2 .LIB CRC = 78 33 9 | --> FILE: FORMAT .LIB CRC = F9 17 10 | --> FILE: FILE2 .LIB CRC = 58 D0 11 | --> FILE: MORELIB .LIB CRC = EB 57 12 | --> FILE: NUMIO2 .LIB CRC = 0F C6 13 | --> FILE: WSCLEAN .COM CRC = E0 3F 14 | --> FILE: WSCLEAN .C CRC = 94 82 15 | --> FILE: ZSC .COM CRC = 31 25 16 | --> FILE: ZSC .DOC CRC = 6E 8B 17 | --> FILE: OPT .C CRC = 2C 9A 18 | --> FILE: -CATALOG.42- CRC = 04 44 19 | --> FILE: ZSC-2 .CQ CRC = 4A 79 20 | --> FILE: ZSC-1 .CQ CRC = 34 62 21 | --> FILE: ZSC-C .LIB CRC = A3 35 22 | --> FILE: ZSM .COM CRC = D9 93 23 | --> FILE: ZSM .DOC CRC = AA 3F 24 | --> FILE: OPT .COM CRC = CD 29 25 | --> FILE: CCO .SUB CRC = BF 33 26 | --> FILE: STRING .LIB CRC = B7 26 27 | --> FILE: OPT .DOC CRC = 7A 11 28 | --> FILE: USQ .COM CRC = 56 21 29 | --> FILE: CRC .COM CRC = B2 07 -------------------------------------------------------------------------------- /small_c_17/CRUN2.LIB: -------------------------------------------------------------------------------- 1 | #asm 2 | TRUE EQU 1 3 | FALSE EQU 0 4 | ORG 100H 5 | ; 6 | ; TAKE COMMAND BUFFER AND BUILD POINTER LIST 7 | ; This first bit is taken from Mike Bernson's Small-C 8 | ; in the CUG library.(+ Minor Z80 mods) 9 | ccinit: 10 | LD HL,(6) ;Point to high memory and use 11 | DEC HL ;it to get suitable value for SP 12 | LD SP,HL 13 | LD HL,80H ;Save command line 14 | LD DE,ccmdbuf 15 | LD BC,50H ;Assumed max line length 16 | LDIR 17 | LD HL,ccmdbuf 18 | LD E,(HL) 19 | LD D,0 20 | ADD HL,DE 21 | INC HL 22 | LD (HL),0 23 | LD DE,cchptr 24 | LD HL,ccmdbuf 25 | LD BC,1 26 | ccinit2: 27 | INC HL 28 | LD A,(HL) 29 | OR A 30 | JP Z,ccinit4 31 | CP ' ' 32 | JP Z,ccinit2 33 | LD A,L 34 | LD (DE),A 35 | LD A,H 36 | INC DE 37 | LD (DE),A 38 | INC DE 39 | INC C 40 | ccinit3: 41 | INC HL 42 | LD A,(HL) 43 | OR A 44 | JP Z,ccinit4 45 | CP ' ' 46 | JP NZ,ccinit3 47 | LD (HL),0 48 | JP ccinit2 49 | ccinit4: 50 | LD HL,cchptr-2 51 | PUSH BC ;argc 52 | PUSH HL ;argv 53 | CALL main 54 | JP 0 55 | ccmdbuf: DEFS 50H ;Memory to which command line is moved 56 | DEFW ccNULL 57 | cchptr: 58 | DEFW ccNULL,ccNULL,ccNULL,ccNULL,ccNULL 59 | DEFW ccNULL,ccNULL,ccNULL,ccNULL,ccNULL 60 | DEFW ccNULL,ccNULL,ccNULL,ccNULL,ccNULL 61 | DEFW ccNULL,ccNULL,ccNULL,ccNULL,ccNULL 62 | DEFW ccNULL,ccNULL,ccNULL,ccNULL,ccNULL 63 | ccNULL: 64 | DEFB 'NONAME',0 65 | ; ****** ESSENTIAL RUN-TIME ROUTINES ******* 66 | ; 67 | ; Based on routines by R.Cain in DDJ no.48 68 | ; 69 | ; Fetch a single byte from (HL) and sign extend into HL 70 | ccgchar: LD A,(HL) 71 | ; Put A into HL and sign extend through H 72 | ccsxt: LD L,A 73 | RLCA 74 | SBC A,A 75 | LD H,A 76 | RET 77 | ;Fetch a 16 bit integer from (HL) to HL 78 | ccgint: LD A,(HL) 79 | INC HL 80 | LD H,(HL) 81 | LD L,A 82 | RET 83 | ;Move a single byte from HL to (DE) 84 | ccpchar: LD A,L 85 | LD (DE),A 86 | RET 87 | ; Move a 16 bit integer in HL to (DE) 88 | ccpint: LD A,L 89 | LD (DE),A 90 | INC DE 91 | LD A,H 92 | LD (DE),A 93 | RET 94 | ; Inclusive or HL and DE to HL 95 | ccor: LD A,L 96 | OR E 97 | LD L,A 98 | LD A,H 99 | OR D 100 | LD H,A 101 | RET 102 | ; Exclusive or HL and DE into HL 103 | ccxor: LD A,L 104 | XOR E 105 | LD L,A 106 | LD A,H 107 | XOR D 108 | LD H,A 109 | RET 110 | ; And HL and DE into HL 111 | ccand: LD A,L 112 | AND E 113 | LD L,A 114 | LD A,H 115 | AND D 116 | LD H,A 117 | RET 118 | ; Compare routines. HL tested against DE 119 | ; HL set to 1 if condition true or 0 if false. 120 | ; 121 | ;HL=DE? 122 | cceq: CALL cccmp 123 | RET Z 124 | DEC HL 125 | RET 126 | ;HL!=DE? 127 | ccne: CALL cccmp 128 | RET NZ 129 | DEC HL 130 | RET 131 | ;DE>HL? (signed) 132 | ccgt: EX DE,HL 133 | JP cclt 134 | ; DE<=HL? (signed) 135 | ccle: CALL cccmp 136 | RET Z 137 | RET C 138 | DEC HL 139 | RET 140 | ; DE>=HL? (signed) 141 | ccge: CALL cccmp 142 | RET NC 143 | DEC HL 144 | RET 145 | ; DE=HL? (unsigned) 166 | ccuge: CALL ccucmp 167 | RET NC 168 | DEC HL 169 | RET 170 | ; DEHL? (unsigned) 176 | ccugt: EX DE,HL 177 | JP ccult 178 | ; DE<=HL? (unsigned) 179 | ccule: CALL ccucmp 180 | RET Z 181 | RET C 182 | DEC HL 183 | RET 184 | ; Unsigned compare. C set if DEHL? (signed) 78 | ccgt: EX DE,HL 79 | JP cclt 80 | ; DE<=HL? (signed) 81 | ccle: CALL cccmp 82 | RET Z 83 | RET C 84 | DEC HL 85 | RET 86 | ; DE>=HL? (signed) 87 | ccge: CALL cccmp 88 | RET NC 89 | DEC HL 90 | RET 91 | ; DE=HL? (unsigned) 112 | ccuge: CALL ccucmp 113 | RET NC 114 | DEC HL 115 | RET 116 | ; DEHL? (unsigned) 122 | ccugt: EX DE,HL 123 | JP ccult 124 | ; DE<=HL? (unsigned) 125 | ccule: CALL ccucmp 126 | RET Z 127 | RET C 128 | DEC HL 129 | RET 130 | ; Unsigned compare. C set if DEFCB,HL=Filename 97 | PUSH DE 98 | LD DE,ccOUTBF 99 | CALL ccSDMA ;Set DMA for O/P 100 | POP DE 101 | CALL ccDELFL ;Delete if needed 102 | CALL ccCREFL ;Create file 103 | JP Z,ccDIRFL ;Directory full error 104 | XOR A ;Set O/P buffer pointer 105 | LD (ccOBP),A 106 | INC A 107 | LD (ccOFLG),A ;Mark o/p file open 108 | JP ccsxt ; And return with Channel 1 in HL 109 | ; 110 | ; Compare two 4 byte strings pointed to by HL and DE 111 | ; return Z and A=0 if matched 112 | ; 113 | ccCMPST: LD B,4 114 | ccCMPS1: LD A,(HL) 115 | CALL ccCAPST ;Convert to U/C 116 | EX DE,HL 117 | CP (HL) 118 | EX DE,HL 119 | RET NZ ;Match failed 120 | INC HL 121 | INC DE 122 | DEC B 123 | JP NZ,ccCMPS1 124 | XOR A ;Set Z and zero A 125 | RET 126 | ; 127 | ; Open a read file for ccGNB routine 128 | ; Enter with HL->filename 129 | ; 130 | ccROPN1: LD A,(ccINFLG) ;Check if i/p channel is in use 131 | CP 0 ;0 if OK 132 | JP NZ,ccFLINU ;Error message and return 133 | LD DE,ccFCBI ;Point to FCB for read file 134 | CALL ccSFCB ;Go and set FCB 135 | PUSH DE 136 | LD DE,ccINBUF 137 | CALL ccSDMA ;Set up DMA for I/P 138 | POP DE 139 | CALL ccOPNFL ;Return with Z set if not there 140 | JP Z,ccNOFIL 141 | LD A,1 ;Mark file as open 142 | LD (ccINFLG),A 143 | XOR A ;Set EOF flag to show that EOF has not yet been reached 144 | LD (ccFENDF),A 145 | LD A,80H 146 | LD (ccIBP),A ;Force initial read when accessed 147 | LD HL,2 ;Return with channel no. in HL 148 | RET 149 | ; 150 | ; Close a file. Switch off and ccCONFG 151 | ; Function format: fclose(iochannel) 152 | ; if iochannel=0, ^Z is not added to 153 | ; end of write file if it is open. 154 | ; 155 | fclose: LD A,L ;CHECK CHANNEL NO. 156 | CP 2 157 | JP Z,ccFCLS3 ;Read file 158 | LD A,(ccCONFG) ;Is there one to close? 159 | CP 1 160 | JP Z,ccFCLS2 ;No. O/P was to CON: 161 | XOR A 162 | CP L ; Check if CZ is to be omitted iochannel=0 163 | JP Z,ccFCLS1 164 | LD A,CZ ;EOF to write file 165 | CALL ccWNB 166 | ccFCLS1: LD L,1 ; reset to the write channel no. 167 | LD DE,ccOUTBF 168 | CALL ccSDMA 169 | LD DE,ccFCBO 170 | CALL ccDWRT ;Flush write buffer to disk 171 | CALL ccCLSFL ;Close write file 172 | ccFCLS2: XOR A 173 | LD (ccOFLG),A ;Mark O/P file closed 174 | LD (ccCONFG),A 175 | LD (ccLSTFG),A ;LST: off 176 | RET 177 | ccFCLS3: XOR A ;Mark read file closed 178 | LD (ccINFLG),A 179 | RET 180 | ; 181 | ; Test for EOF in a read file. 182 | ; Function format: eof() Returns 0 until an attempt is made to 183 | ; read a sector beyond the end of the file 184 | ; 185 | eof: LD A,(ccFENDF) 186 | JP ccsxt 187 | ; 188 | ; Exit after closing write files 189 | ; Function format: exit() 190 | ; 191 | exit: LD HL,1 192 | PUSH HL ;Write channel 193 | LD A,(ccOFLG) 194 | OR A ;Z if write closed 195 | CALL NZ,fclose 196 | XOR A ; Reset ccINFLG 197 | LD (ccINFLG),A 198 | JP 0 199 | ; 200 | ; Set up FCB. Enter with DE->FCB , HL->File name, AF,DE preserved 201 | ; 202 | ccSFCB: PUSH AF 203 | PUSH HL 204 | PUSH DE 205 | CALL ccCFCB ;Pad out FCB with 20H and set NR and EXT to 0 206 | POP DE ;FCB 207 | POP HL ;Name 208 | LD (ccFNST),HL 209 | PUSH DE ;Still save FCB 210 | ccSFCB1: LD A,(HL) ;Skip blanks 211 | CP 20H 212 | INC HL 213 | JP Z,ccSFCB1 214 | LD A,(HL) 215 | CP ':' ;Drive given? 216 | DEC HL 217 | JP NZ,ccSFCB2 ;Use default 218 | LD A,(HL) 219 | CALL ccCAPST 220 | SUB '@' 221 | LD (DE),A 222 | INC HL 223 | INC HL ;Point to name 224 | JP ccSFCB3 225 | ccSFCB2: XOR A ;Use default drive 226 | LD (DE),A 227 | ccSFCB3: INC DE 228 | LD B,8 229 | ccSFCB4: LD A,(HL) ;Move filename to FCB 230 | CALL ccCAPST ; -> U/C 231 | CP '.' 232 | JP Z,ccSFCB5 233 | CP 0 ; End? 234 | JP Z,ccSFCB7 235 | LD (DE),A 236 | INC HL 237 | INC DE 238 | DEC B 239 | JP NZ,ccSFCB4 ;Keep looping until '.' 240 | ccSFCB5: LD A,(HL) 241 | CP 0 ;End of string? 242 | JP Z,ccSFCB7 ;Exit 243 | CP 20H 244 | JP Z,ccSFCB7 245 | CP '.' 246 | INC HL 247 | JP NZ,ccSFCB5 ;Keep looping if name not done 248 | LD B,3 249 | POP DE ;Get FCB start 250 | PUSH DE 251 | PUSH HL ;Save pointer to type 252 | LD HL,9 253 | ADD HL,DE 254 | EX DE,HL ;Point DE to type in FCB 255 | POP HL 256 | ccSFCB6: LD A,(HL) 257 | CALL ccCAPST 258 | CP 0 259 | JP Z,ccSFCB7 260 | LD (DE),A 261 | INC HL 262 | INC DE 263 | DEC B 264 | JP NZ,ccSFCB6 265 | ccSFCB7: POP DE ;Exit. DE->FCB 266 | POP AF 267 | RET 268 | ; 269 | ; CLEAR OUT FCB WITH BLANKS & 0's IN NR & EX 270 | ; 271 | ccCFCB: PUSH DE 272 | POP HL 273 | LD (HL),0 ;Set default drive 274 | INC HL 275 | LD A,20H 276 | LD B,11 277 | ccCFCB1: LD (HL),A 278 | INC HL 279 | DEC B 280 | JP NZ,ccCFCB1 281 | XOR A 282 | LD (HL),A ;EX 283 | LD HL,20H ;Point to NR 284 | ADD HL,DE 285 | LD (HL),A 286 | RET 287 | ; 288 | ; Set letters to U/C 289 | ; 290 | ccCAPST: CP 61H ;'a' 291 | RET C 292 | CP 7BH ;'z'+1 293 | RET NC 294 | SUB 20H 295 | RET 296 | ; 297 | ; Print out file name 298 | ; 299 | ccPFILE: PUSH HL 300 | CALL crlf 301 | LD HL,(ccFNST) 302 | PUSH HL 303 | CALL puts 304 | POP HL 305 | POP HL 306 | RET 307 | ; 308 | ccDIRFL: CALL ccPFILE ; Print file name 309 | LD DE,ccDFLM ;Print 'Directory full' message 310 | ccDFUL1: CALL ccPMESS 311 | LD HL,0 ;Error indicator 312 | RET 313 | ; 314 | ccNOFIL: CALL ccPFILE 315 | LD DE,ccNOFLM ;Print 'No such file' message 316 | JP ccDFUL1 317 | ; 318 | ccFCMSG: LD DE,ccFCERR ;Print 'File closed' message 319 | CALL ccPMESS 320 | LD A,0FFH ;Error code 321 | JP ccsxt 322 | ccFLINU: CALL ccPFILE 323 | LD DE,ccFIUM ;Print 'File Channel in use' 324 | JP ccDFUL1 325 | ; 326 | ccCONST: DEFB 'CON:' ;CON: string for comparison in ccWOPN1 327 | ccLSTST: DEFB 'LST:' ;LST: string 328 | ; 329 | ; File Messages 330 | ; 331 | ccNOFLM: DEFB ' No such file' 332 | DEFW 0A0DH 333 | DEFB '$' 334 | ccDFLM: DEFB ' Disk/Directory full' 335 | DEFW 0A0DH 336 | DEFB '$' 337 | ccFMERR: DEFB ' File Mode Error' 338 | DEFW 0A0DH 339 | DEFB '$' 340 | ccFIUM: DEFB ' Read or Write file channel in use' 341 | DEFW 0A0DH 342 | DEFB '$' 343 | ccFCERR: DEFW 0A0DH 344 | DEFB 'File not open' 345 | DEFW 0A0DH 346 | DEFB '$' ; 347 | ; 348 | ; FLAG BYTES 349 | ; 350 | ccCONFG: DEFB 0 ;Flag to show that CON: is the O/P file 351 | ccFENDF: DEFB 0 ;Flag to show that EOF hasn't been reached during a read 352 | ccINFLG: DEFB 0 ;Flag to show that i/p channel is in use 353 | ccOFLG: DEFB 0 ;O/p channel in use (1 if in use) 354 | ccFNST: DEFS 2 ;Pointer to file name 355 | ; 356 | ; 357 | ; ASSORTED DISK ROUTINES - MANY BASED ON THOSE IN CPMUG VOL 16. 358 | ; 359 | ; 'ccENTRY' is a general register saver for use with BDOS calls. 360 | ; 361 | ccENTRY: PUSH HL 362 | PUSH DE 363 | PUSH BC 364 | CALL ccBDOS 365 | POP BC 366 | POP DE 367 | POP HL 368 | RET 369 | ; 370 | ; ccDELFL - DELETE FILE. FCB POINTED BY DE 371 | ; HL, DE, BC PRESERVED 372 | ; 373 | ccDELFL: PUSH BC 374 | LD C,19 ;DELETE 375 | CALL ccENTRY 376 | POP BC ;NO EXIT CONDS 377 | RET 378 | ; 379 | ; ccPMESS - PRINTS OUT MESSAGE ->DE UNTIL $ 380 | ; ALL REGS SAVED 381 | ; 382 | ccPMESS: PUSH AF 383 | PUSH BC 384 | LD C,9 385 | CALL ccENTRY 386 | POP BC 387 | POP AF 388 | RET 389 | ; 390 | ; ccOPNFL OPEN AN EXISTING FILE WHOSE FCB IS POINTED TO BY DE 391 | ; FILE NAME AND DRIVE IN FCB ALREADY. EXIT WITH Z SET IF NO SUCH FILE. 392 | ; HL, DE, BC PRESERVED 393 | ; 394 | ccOPNFL: PUSH HL 395 | PUSH BC 396 | LD HL,12 397 | ADD HL,DE 398 | LD (HL),0 ;ZERO EXTENT 399 | LD HL,32 400 | ADD HL,DE 401 | LD (HL),0 ;ZERO NR 402 | LD C,15 ;OPEN 403 | CALL ccENTRY 404 | CP 0FFH ;Z IF NONE 405 | POP BC 406 | POP HL 407 | RET 408 | ; 409 | ; ccCLSFL - CLOSE FILE WHOSE FCB IS POINTED TO BY DE 410 | ; HL, DE, AND BC PRESERVED. RETURNS Z SET IF NOT PRESENT 411 | ; 412 | ccCLSFL: PUSH BC 413 | LD C,16 ;CLOSE 414 | CALL ccENTRY 415 | POP BC 416 | CP 0FFH ; Z IF NOT PRESENT 417 | RET 418 | ; 419 | ; ccCREFL - CREATE FILE WHOSE FCB IS POINTED TO BY DE 420 | ; HL, DE, BC PRESERVED. Z SET IF NO DIR SPACE 421 | ; 422 | ccCREFL: PUSH BC 423 | LD C,22 ;MAKE FILE 424 | CALL ccENTRY 425 | CP 0FFH ;Z IF NO SPACE 426 | POP BC 427 | RET 428 | ; 429 | ; ccSDMA - SET DMA BUFFER TO ADDRESS IN DE 430 | ; HL, DE, BC PRESERVED. 431 | ; 432 | ccSDMA: PUSH BC 433 | LD C,26 ;DMA SET 434 | CALL ccENTRY 435 | POP BC 436 | RET 437 | ; 438 | ; ccDREAD - READ A FILE SECTOR. DE POINTS TO FCB 439 | ; HL, DE, BC PRESERVED 440 | ; 441 | ccDREAD: PUSH BC 442 | LD C,20 ;READ SECTOR 443 | CALL ccENTRY 444 | CP 0 ;Z SET IF NORMAL 445 | POP BC 446 | RET 447 | ; 448 | ; ccDWRT - WRITE A FILE SECTOR. DE POINTS TO FCB 449 | ; HL, DE, BC PRESERVED 450 | ; 451 | ccDWRT: PUSH BC 452 | LD C,21 ;WRITE SECTOR 453 | CALL ccENTRY 454 | CP 0 ;Z SET IF NORMAL 455 | POP BC 456 | RET 457 | ; 458 | ; 459 | ; WRITE NEXT BYTE TO FILE VIA STANDARD BUFFER AT 80H WITH THE 460 | ; STANDARD FCB. 461 | ; 462 | ccWNB: PUSH HL 463 | PUSH DE 464 | PUSH AF 465 | LD A,(ccOBP) 466 | CP 80H 467 | JP NZ,ccWNB0 468 | LD DE,ccOUTBF 469 | CALL ccSDMA ;SET FOR STANDARD O/P BUFF 470 | LD DE,ccFCBO 471 | CALL ccDWRT ;WRITE 1 SECTOR 472 | JP Z,ccWNB00 ;OK 473 | LD DE,ccWERR 474 | CALL ccPMESS 475 | JP 0H ;WARM START 476 | ccWERR: CALL ccPFILE 477 | DEFB ' Write Error' 478 | DEFW 0A0DH 479 | DEFB '$' 480 | ccWNB00: XOR A ;ZERO COUNT IF NEW BUFF 481 | ccWNB0: LD E,A 482 | LD D,0 483 | INC A 484 | LD (ccOBP),A 485 | LD HL,ccOUTBF 486 | ADD HL,DE 487 | POP AF 488 | LD (HL),A 489 | POP DE 490 | POP HL 491 | RET 492 | ; 493 | ccOBP: DEFS 1 ;O/P BUFFER COUNTER 494 | ;ccOUTBF: DEFS 80H ;Currently set at CP/M default buffer 495 | ;ccFCBO: DEFS 36 ;Currently set at 5CH 496 | ; 497 | ; GET NEXT BYTE FROM I/P BUFFER ccINBUF AND REFILL WHEN EXHAUSTED 498 | ; 499 | ccGNB: PUSH DE 500 | LD A,(ccFENDF) ;EOF? 501 | CP 0 502 | JP NZ,ccGNB1 503 | LD A,(ccIBP) 504 | CP 80H ;Refill needed? 505 | JP NZ,ccGNB0 506 | PUSH HL 507 | PUSH BC 508 | LD DE,ccINBUF 509 | CALL ccSDMA 510 | LD DE,ccFCBI 511 | CALL ccDREAD 512 | POP BC 513 | POP HL 514 | JP NZ,ccGNB1 ;Past end of file 515 | XOR A 516 | ccGNB0: LD E,A 517 | LD D,0 518 | INC A 519 | LD (ccIBP),A 520 | PUSH HL 521 | LD HL,ccINBUF 522 | ADD HL,DE 523 | LD A,(HL) 524 | POP HL 525 | POP DE 526 | RET 527 | ccGNB1: LD A,0FFH ;EOF keep sending -1 528 | LD (ccFENDF),A 529 | POP DE 530 | RET 531 | ; 532 | ccIBP: DEFS 1 533 | ccINBUF: DEFS 80H ;Input buffer if needed 534 | ccFCBI: DEFS 36 ;FCB if needed 535 | ; END 536 | #endasm 537 | S 36 ;FCB if needed 538 | ; END 539 | #endasm 540 | ndasm 541 | eded 542 | ccFCBI: DEFS -------------------------------------------------------------------------------- /small_c_17/FORMAT.LIB: -------------------------------------------------------------------------------- 1 | /* Formatted I/O for Small-C plus various other I/O functions */ 2 | 3 | /* 4 | The printf,fprintf,sprintf,scanf,fscanf and sscanf function names are 5 | recognised by the compiler and it gives them an extra argument after the 6 | others which equals the number of actual arguments that occured in the 7 | function call. This allows variable numbers of arguments. 8 | */ 9 | 10 | #asm 11 | ccnbuff: DEFS 10 ;Small I/P buffer for getdec and gethex 12 | #endasm 13 | 14 | /* 15 | getdec() Inputs a decimal number. Uses ccnbuff as I/P buffer 16 | putdec(n) Outputs a decimal number 17 | gethex() Inputs a hex number. Uses ccnbuff as I/P buffer 18 | putbyte(ch) Outputs an 8 bit number as 2 hex digits 19 | puthex(n) Outputs a 16 bit number as 4 hex digits 20 | atoi(ptr) Returns an integer pointed to by ptr 21 | hextoi(ptr) Returns integer value of hex number pointed to by ptr 22 | printf(format,args...) %d,%x,%s,%c supported with optional fields 23 | sprintf(pointer,format,args...) .. ditto .. 24 | fprintf(chan,format,args...) .. ditto .. 25 | scanf(format,&args..) only %d and %x supported 26 | sscanf(pointer,format,&args...) .. .. .. 27 | fscanf(chan,format,&args...) .. .. .. 28 | fputs(pointer,chan) send string to file 29 | sputs(source_pointer,dest_pointer) move string to new destination 30 | fputdec(number,chan) send dec no. to file 31 | fputhex(number,chan) send 4 digit hex no to file 32 | fgets(pointer,chan) get string from file to buffer until 0,EOF or CR 33 | Sets EOF flag used by eof() if EOF is encountered. 34 | */ 35 | 36 | /* 37 | I/P a signed decimal number 38 | */ 39 | getdec() 40 | { 41 | char *ptr; 42 | ptr=ccnbuff; 43 | putchar('?'); /* Prompt */ 44 | gets(ptr); 45 | return atoi(ptr); 46 | } 47 | /* 48 | Get char. from buffer, check if numeric and return value or -1 49 | */ 50 | ccnum(ptr) 51 | char *ptr; 52 | {char c; 53 | c=*ptr&127; /* Mask off top bit */ 54 | if((c<'0')|(c>'9')) return -1; 55 | return c-'0';} 56 | 57 | /* 58 | Output a signed decimal number 59 | */ 60 | #asm 61 | putdec: XOR A 62 | ccpd1: LD (ccspflg),A 63 | JP ccpdec 64 | fputdec: POP BC 65 | POP HL 66 | POP DE 67 | PUSH HL 68 | PUSH DE 69 | PUSH BC ;Reshuffle args 70 | LD A,1 71 | JR ccpd1 72 | ; 73 | ; Similar stuff for hex 74 | puthex: XOR A 75 | ccphx1: LD (ccspflg),A 76 | JP ccphex 77 | fputhex: POP BC 78 | POP HL 79 | POP DE 80 | PUSH HL 81 | PUSH DE 82 | PUSH BC 83 | LD A,1 84 | JR ccphx1 85 | #endasm 86 | 87 | ccpdec(och,n) 88 | int och,n; 89 | {if(n<0){n=-n; ccpchr(och,'-');} 90 | if((n/10)!=0) 91 | ccpdec(och,n/10); 92 | ccpchr(och,n%10+'0'); 93 | } 94 | 95 | /* 96 | Input a hex number. Similar to getdec() 97 | */ 98 | gethex() 99 | {int digval,n; 100 | char *ptr; 101 | n=0; 102 | ptr=ccnbuff; 103 | putchar('$'); /* Prompt */ 104 | gets(ptr); 105 | return hextoi(ptr);} 106 | 107 | /* 108 | Get char. from buffer. Check if hex. Return value or -1 109 | */ 110 | cchex(ptr) 111 | char *ptr; 112 | {char c; 113 | c=*ptr&127; 114 | if((c>='0')&(c<='9')) return c-'0'; 115 | if((c>='A')&(c<='F')) return c-55; 116 | if((c>='a')&(c<='f')) return c-87; 117 | return -1;} 118 | 119 | /* 120 | Output a byte in hex 121 | */ 122 | #asm 123 | putbyte: XOR A 124 | LD (ccspflg),A 125 | JP ccpbyte 126 | #endasm 127 | 128 | ccpbyte(och,byte) 129 | int och; 130 | char byte; 131 | { char temp; 132 | temp=(byte>>4)&15; 133 | ccptnib(och,temp); 134 | temp=byte&15; 135 | ccptnib(och,temp);} 136 | 137 | /* 138 | Output nibble 139 | */ 140 | ccptnib(och,ch) 141 | int och; 142 | char ch; 143 | { if(ch<10)ccpchr(och,ch+48); 144 | else ccpchr(och,ch+55);} 145 | 146 | /* 147 | Output a 16 bit hex number 148 | */ 149 | ccphex(och,ptr) 150 | int och; 151 | char *ptr; 152 | { char temp; 153 | temp=ptr>>8; 154 | ccpbyte(och,temp); 155 | temp=ptr; 156 | ccpbyte(och,temp);} 157 | 158 | /* 159 | Get a signed integer from a string in memory 160 | */ 161 | atoi(ptr) 162 | char *ptr; 163 | {int digval,sign,n; 164 | n=0; 165 | sign=1; 166 | while(*ptr==' ')ptr++; 167 | if(*ptr=='-'){sign=-1;ptr++;} 168 | while(*ptr) 169 | {digval=ccnum(ptr++); 170 | if(digval==-1)break; 171 | n=digval+n*10;} 172 | return n*sign;} 173 | 174 | /* 175 | Get hex value from string in memory 176 | */ 177 | hextoi(ptr) 178 | char *ptr; 179 | {int digval,n; 180 | n=0; 181 | while(*ptr==' ')ptr++; 182 | while(*ptr) 183 | {digval=cchex(ptr++); 184 | if(digval==-1)break; 185 | n=digval+n*16;} 186 | return n; 187 | } 188 | 189 | /* 190 | Flag for scanf and printf function family and their supporting functions 191 | to mark the type of I/O: Value = 0 for CON:,1 for file, 2 for memory 192 | */ 193 | char ccspflg; 194 | 195 | #asm 196 | scanf: LD A,0 197 | LD (ccspflg),A 198 | JP ccscan 199 | fscanf: LD A,1 200 | LD (ccspflg),A 201 | JP ccscan 202 | sscanf: LD A,2 203 | LD (ccspflg),A 204 | JP ccscan 205 | #endasm 206 | /* 207 | Core routine for "scanf" function family 208 | */ 209 | ccscan(nargs) 210 | int nargs; 211 | {int *argptr,argno,argin,*iptr,iochan; 212 | char *fptr,chvalue,*bptr,*mptr,ibuf[80]; 213 | argno=nargs; 214 | argin=0; 215 | argptr=&nargs; 216 | /* Search stack for actual args */ 217 | while(argno--)argptr++; 218 | if(ccspflg)mptr=*argptr--; /*Extra arg for sscanf & fscanf*/ 219 | fptr=*argptr--; 220 | switch(ccspflg) 221 | {case 0:gets(ibuf);bptr=ibuf;break; 222 | case 1:iochan=mptr;fgets(ibuf,iochan);bptr=ibuf;break; 223 | case 2:bptr=mptr; 224 | } 225 | while(*fptr) 226 | {iptr=*argptr; 227 | while(*fptr!='%')fptr++;fptr++; 228 | while(*bptr==' ')bptr++; 229 | if((*bptr==0)|(*bptr==0x0d))break; 230 | switch(chvalue=*fptr++) 231 | {case 'd': 232 | while((ccnum(bptr)==-1)&(*bptr!='-')) 233 | {if((*bptr==0x0d)|(*bptr==0))break;bptr++;} 234 | *iptr=atoi(bptr); 235 | if(*bptr=='-')bptr++; 236 | argptr--; 237 | argin++; 238 | while(ccnum(bptr)!=-1)bptr++; 239 | break; 240 | case 'x': 241 | while(cchex(bptr)==-1) 242 | {if((*bptr==0x0d)|(*bptr==0))break;bptr++;} 243 | if(*bptr=='0'){bptr++; /* Skip 0x leaders */ 244 | if((*bptr=='x')|(*bptr=='X'))bptr++;else bptr--;} 245 | *iptr=hextoi(bptr); 246 | argptr--; 247 | argin++; 248 | while(cchex(bptr)!=-1)bptr++; 249 | break; 250 | } 251 | } 252 | return argin; 253 | } 254 | 255 | #asm 256 | printf: XOR A 257 | LD (ccspflg),A 258 | JP ccpf 259 | fprintf: LD A,1 260 | LD (ccspflg),A 261 | JP ccpf 262 | sprintf: LD A,2 263 | LD (ccspflg),A 264 | JP ccpf 265 | #endasm 266 | 267 | /* 268 | Core routine for printf family 269 | Supports %d,%x,%c,%s with optional fields 270 | */ 271 | ccpf(nargs) 272 | int nargs; 273 | {int *argptr,ivalue,argno,field,xtrarg; 274 | char *fptr,*sptr,chvalue; 275 | argno=nargs; 276 | argptr=&nargs; 277 | /* Find actual args */ 278 | while(argno--)argptr++; 279 | xtrarg=0; 280 | if(ccspflg==1)xtrarg= *argptr--;/*Extra arg for sprintf & fprintf*/ 281 | if(ccspflg==2)xtrarg=argptr--; 282 | fptr=*argptr--; 283 | while(*fptr) 284 | { switch(chvalue=*fptr++) 285 | { case 92: switch(*fptr) 286 | { case 'n' : ccpchr(xtrarg,0x0d);ccpchr(xtrarg,0x0a);break; 287 | case 't' : ccpchr(xtrarg,'\t');break; 288 | case 'f' : ccpchr(xtrarg,'\f');break; 289 | case 'b' : ccpchr(xtrarg,'\b');break; 290 | case '0' : ccpchr(xtrarg,0);break; 291 | case 'r' : ccpchr(xtrarg,'\r');break; 292 | default : ccpchr(xtrarg,*fptr); 293 | }fptr++;break; 294 | case '%' : field=ccgetfw(&fptr); 295 | if(*fptr=='d') 296 | {fptr++;ivalue=*argptr--;ccfdec(xtrarg,ivalue,field);break;} 297 | if(*fptr=='x') 298 | {fptr++;ivalue=*argptr--;form0x(xtrarg,ivalue,field);break;} 299 | if(*fptr=='c') 300 | {fptr++;chvalue=*argptr--;formch(xtrarg,chvalue,field);break;} 301 | if(*fptr=='s') 302 | {fptr++;formstg(xtrarg,*argptr--,field);break;} 303 | default:ccpchr(xtrarg,chvalue); 304 | } 305 | } 306 | } 307 | /* Get a field width and update pointer to char after width */ 308 | ccgetfw(ptbuff) 309 | int *ptbuff;/* Actually a pointer to a char pointer */ 310 | {char *bptr; 311 | int fval; 312 | bptr=*ptbuff; 313 | fval=0; 314 | while(ccnum(bptr)!= -1){fval=fval*10+ccnum(bptr++);} 315 | *ptbuff=bptr; 316 | return fval; 317 | } 318 | 319 | /* Output decimal number in field of specified width*/ 320 | ccfdec(och,n,fwidth) 321 | int och,n,fwidth; 322 | {char *ptr,sign; 323 | int i,n1; 324 | n1=n; 325 | if(fwidth<=0){ccpdec(och,n);return;} 326 | sign=' '; 327 | if(n<0){n=-n;sign='-';} 328 | while(fwidth>8){fwidth--;ccpchr(och,' ');} 329 | ptr=ccnbuff; 330 | i=fwidth; 331 | while(fwidth--)*ptr++=' '; 332 | *ptr-- =0; 333 | if(n==0){*ptr-- ='0';fwidth++;} 334 | while((i>=fwidth++)&(n>0)){if(ptr==ccnbuff){ccpdec(och,n1);return;} 335 | *ptr-- =n%10+'0';n=n/10;} 336 | *ptr=sign; 337 | ccputs(ccnbuff,och); 338 | } 339 | 340 | /* Output a 4 digit hex number preceded by '0x' */ 341 | form0x(och,n,fwidth) 342 | int och,n,fwidth; 343 | {while(fwidth>6){fwidth--;ccpchr(och,' ');} 344 | ccputs("0x",och); 345 | ccphex(och,n); 346 | } 347 | 348 | /*Output char in field (no check for control chars)*/ 349 | formch(och,ch,fwidth) 350 | char ch; 351 | int och,fwidth; 352 | { if(fwidth<=0)fwidth=1; 353 | while(--fwidth)ccpchr(och,' '); 354 | ccpchr(och,ch); 355 | } 356 | 357 | /* 358 | Output string in field. Backslash chars will mess up field calculation 359 | */ 360 | formstg(och,strptr,fwidth) 361 | char *strptr; 362 | int och,fwidth; 363 | { 364 | int len; 365 | char *chptr; 366 | chptr=strptr; 367 | len=0; 368 | while(*chptr++)len++; 369 | len=fwidth-len; 370 | if(len<0)len=0; 371 | while(len--)ccpchr(och,' '); 372 | ccputs(strptr,och); 373 | } 374 | 375 | /* 376 | O/P char to I/O depending on value of ccspflg 377 | och is 16 bit file channel or a pointer to a char pointer 378 | */ 379 | ccpchr(och,ch) 380 | int *och; 381 | char ch; 382 | {char *ptr; 383 | switch (ccspflg) 384 | {case 0: putchar(ch);return; 385 | case 1: return putc(ch,och); 386 | case 2: ptr=*och;*ptr= ch;*och= ++ptr; 387 | } 388 | } 389 | /*fputs(pointer,chan) No termination of string in file 390 | but expects NULL at end of pointed string*/ 391 | 392 | fputs(ptr,och) 393 | int och; 394 | char *ptr; 395 | {char ch; 396 | while(ch= *ptr++){if(ch==0x0d){putc(ch,och);ch=0x0a;} 397 | if(ch==92){ch=*ptr++; 398 | switch(ch) 399 | {case 'n': putc(0x0d,och);ch=0x0a; 400 | case 't': ch='\t'; 401 | case 'r': ch='\r'; 402 | case 'f': ch='\f'; 403 | case '0': ch=0; 404 | }} 405 | putc(ch,och);} 406 | } 407 | 408 | /* 409 | Similar routine for sending string to memory 410 | sputs(source_ptr,target_ptr) NULLs on both strings 411 | */ 412 | sputs(ptr,tptr) 413 | char *ptr,*tptr; 414 | {while(*tptr++ = *ptr++);*tptr=0; 415 | } 416 | 417 | ccputs(ptr,och) 418 | char *ptr; 419 | int och; 420 | { 421 | switch(ccspflg) 422 | {case 0:puts(ptr);return; 423 | case 1:fputs(ptr,och);return; 424 | case 2:sputs(ptr,och);return;} 425 | } 426 | 427 | /* 428 | Not very like the UNIX version. 429 | fgets(ptr,chan) gets string from file until NULL, EOF or CR 430 | Next byte also read in and assumed to be LF if CR 431 | Returns last character in string, (CR,NULL or EOF). 432 | Marks EOF flag in FILE2.LIB if EOF encountered. 433 | */ 434 | fgets(ptr,och) 435 | char *ptr; 436 | int och; 437 | {char ch; 438 | if(eof()){*ptr=0;return 0x1a;} 439 | while(ch=getc(och)) 440 | {if(ch==0x0d){getc(och);*ptr++ = ch;*ptr++ =0x0a;break;} 441 | if(ch==0x1a)break; 442 | *ptr++ = ch; 443 | } 444 | *ptr=0; 445 | if(ch==0x1a){ptr=ccFENDF;*ptr=1;} /* Mark EOF */ 446 | return ch; 447 | } 448 | ler to other CPU's. It's 449 | also quite a good introductory low priced text on C in general. 450 | 451 | "The C Programming -------------------------------------------------------------------------------- /small_c_17/MORELIB.LIB: -------------------------------------------------------------------------------- 1 | #asm 2 | ; Assorted routines derived from libraries supplied with 3 | ; Mike Bernson's Small C. 4 | ; TRUE, FALSE defined in CRUN.LIB 5 | ; 6 | ; toupper 7 | ; 8 | ; FUNCTION: TO SHIFT LOWER CASE CHARACTER TO UPPER 9 | ; 10 | ; Format: toupper(CHAR) 11 | ; 12 | toupper: 13 | LD A,L 14 | CP 61H 15 | RET C 16 | CP 7BH 17 | RET NC 18 | AND 5FH 19 | LD L,A 20 | RET 21 | 22 | ; 23 | ; tolower 24 | ; 25 | ; FUNCTION: TO CONVERT CHARACTER TO LOWER CASE 26 | ; 27 | ; Format: tolower(CHAR) 28 | ; 29 | tolower: 30 | LD A,L 31 | CP 'A' 32 | RET C 33 | CP 'Z'+1 34 | RET NC 35 | ADD A,20H 36 | LD L,A 37 | RET 38 | ; 39 | ; isalpha 40 | ; 41 | ; FUNCTION CHECK TO SEE IF ALPHA CHARACTER a-z OR A-Z ONLY 42 | ; 43 | ; Format: isalpha(CHAR) 44 | ; 45 | isalpha: 46 | PUSH HL 47 | CALL isupper 48 | EX DE,HL 49 | POP HL 50 | CALL islower 51 | ADD HL,DE 52 | RET 53 | ; 54 | ; isupper 55 | ; 56 | ; FUNCTION: TO CHECK TO SEE IF CHARACTER IS UPPER CASE 57 | ; 58 | ; Format: isupper(CHAR) 59 | ; 60 | isupper: 61 | LD A,L 62 | CP 'A' 63 | JP C,ccISUP1 64 | CP 'Z'+1 65 | JP NC,ccISUP1 66 | LD HL,TRUE ;Upper case 67 | RET 68 | ccISUP1: 69 | LD HL,FALSE 70 | RET 71 | ; 72 | ; islower 73 | ; 74 | ; FUNCTION: TO CHECK TO SEE IF CHARACTER IS LOWER CASE 75 | ; 76 | ; Format: islower(CHAR) 77 | ; 78 | islower: 79 | LD A,L 80 | CP 'a' 81 | JP C,ccISLW1 82 | CP 'z'+1 83 | JP NC,ccISLW1 84 | LD HL,TRUE ;Lower case 85 | RET 86 | ccISLW1: 87 | LD HL,FALSE ; FALSE 88 | ; 89 | ; 90 | ; isdigit 91 | ; 92 | ; FUNCTION: TO CHECK TO SEE IF CHARACTER IS DIGIT 0-9 ONLY 93 | ; 94 | ; Format: isdigit(CHAR) 95 | ; 96 | isdigit: 97 | LD A,L 98 | CP '0' 99 | JP C,ccISDG1 100 | CP '9'+1 101 | JP NC,ccISDG1 102 | LD HL,TRUE 103 | RET 104 | ccISDG1: 105 | LD HL,FALSE 106 | RET 107 | ; 108 | ; isspace 109 | ; 110 | ; FUNCTION: TO CHECK TO SEE IF WHITE SPACE TAB OR BLANK 111 | ; 112 | ; Format: isspace(CHAR) 113 | ; 114 | isspace: 115 | LD A,L 116 | LD HL,TRUE 117 | CP ' ' 118 | RET Z 119 | CP 9 120 | RET Z 121 | LD HL,FALSE 122 | RET 123 | ; 124 | ; strlen 125 | ; 126 | ; FUNCTION: TO GET THE LENGTH OF A STRING 127 | ; 128 | ; Format: LEN=strlen(STRING) 129 | ; 130 | ; 131 | strlen: 132 | EX DE,HL 133 | LD HL,0 134 | ccSTLN1: 135 | LD A,(DE) 136 | OR A 137 | RET Z 138 | INC HL 139 | INC DE 140 | JP ccSTLN1 141 | ; 142 | ; strcpy 143 | ; 144 | ; FUNCTION: TO COPY FIRST SECOND STRING TO FIRST STRING 145 | ; 146 | ; Format: strcpy(OBJECT,SOURCE) 147 | ; 148 | ; 149 | strcpy: 150 | POP BC 151 | POP DE 152 | POP HL 153 | PUSH HL 154 | PUSH DE 155 | PUSH BC 156 | PUSH HL 157 | ccSCPY1: 158 | LD A,(DE) 159 | LD (HL),A 160 | OR A 161 | JP Z,ccSCPY2 162 | INC HL 163 | INC DE 164 | JP ccSCPY1 165 | ccSCPY2: 166 | POP HL 167 | RET 168 | ; 169 | ; strcat 170 | ; 171 | ; FUNCTION: TO PUT STRING2 AT THEN END OF STRING1 AND RETURN ADDRESS OF 172 | ; STRING 1 173 | ; 174 | ; Format: strcat(STRING1,STRING2) 175 | ; 176 | ; 177 | strcat: 178 | POP BC 179 | POP DE 180 | POP HL 181 | PUSH HL 182 | PUSH DE 183 | PUSH BC 184 | PUSH HL 185 | ccSCAT1: 186 | LD A,(HL) 187 | OR A 188 | JP Z,ccSCAT2 189 | INC HL 190 | JP ccSCAT1 191 | ccSCAT2: 192 | LD A,(DE) 193 | LD (HL),A 194 | OR A 195 | JP Z,ccSCAT3 196 | INC HL 197 | INC DE 198 | JP ccSCAT2 199 | ccSCAT3: 200 | POP HL 201 | RET 202 | ; 203 | ; strpos 204 | ; 205 | ; FUNCTION: TO LOOK FOR STRING 2 IN STRING 1 206 | ; 207 | ; Format: strpos(STRING1,STRING2) 208 | ; 209 | ; 210 | strpos: 211 | POP BC 212 | POP DE 213 | POP HL 214 | PUSH HL 215 | PUSH DE 216 | PUSH BC 217 | LD BC,1 218 | EX DE,HL 219 | ccSTPS1: 220 | LD A,(DE) 221 | OR A 222 | JP Z,ccSTPS5 223 | CP (HL) 224 | JP Z,ccSTPS2 225 | INC DE 226 | INC BC 227 | JP ccSTPS1 228 | ccSTPS2: 229 | PUSH HL 230 | PUSH DE 231 | ccSTPS3: 232 | INC DE 233 | INC HL 234 | LD A,(HL) 235 | OR A 236 | JP Z,ccSTPS4 237 | LD A,(DE) 238 | CP (HL) 239 | JP Z,ccSTPS3 240 | POP DE 241 | POP HL 242 | INC DE 243 | INC BC 244 | JP ccSTPS1 245 | ccSTPS4: 246 | LD L,C ;Found 247 | LD H,B 248 | POP BC 249 | POP BC 250 | RET 251 | ccSTPS5: 252 | LD HL,0 ;Not found 253 | RET 254 | ; 255 | ; 256 | #endasm 257 | PY2: 258 | POP HL 259 | RET 260 | ; 261 | ; strcat 262 | ; 263 | ; FUNCTION: TO PUT STRING2 AT THEN END OF STRING1 AND RETURN ADDRE -------------------------------------------------------------------------------- /small_c_17/NUMIO2.LIB: -------------------------------------------------------------------------------- 1 | /* Numerical I/O Routines for Small C */ 2 | 3 | #asm 4 | ccnbuff: DEFS 10 ;I/P buffer 5 | #endasm 6 | 7 | /* 8 | getdec() Inputs a decimal number. Uses ccnbuff as I/P buffer 9 | putdec(n) Outputs a decimal number 10 | gethex() Inputs a hex number. Uses ccnbuff as I/P buffer 11 | putbyte(ch) Outputs an 8 bit number as 2 hex digits 12 | puthex(n) Outputs a 16 bit number as 4 hex digits 13 | atoi(ptr) Returns an integer from ASCII pointed to by ptr 14 | hextoi(ptr) ......................from hex ASCII no ........ 15 | */ 16 | 17 | /* 18 | I/P a signed decimal number 19 | */ 20 | getdec() 21 | { 22 | char *ptr; 23 | ptr=ccnbuff; 24 | putchar('?'); /* Prompt */ 25 | gets(ptr); 26 | return atoi(ptr); 27 | } 28 | /* 29 | Get char. from buffer, check if numeric and return value or -1 30 | */ 31 | ccnum(ptr) 32 | char *ptr; 33 | {char c; 34 | c=*ptr&127; /* Mask off top bit */ 35 | if((c<'0')|(c>'9')) return -1; 36 | return c-'0';} 37 | 38 | /* 39 | Output a signed decimal number 40 | */ 41 | putdec(n) 42 | int n; 43 | {if(n<0){n=-n; putchar('-');} 44 | if((n/10)!=0) 45 | putdec(n/10); 46 | putchar(n%10+'0'); 47 | } 48 | 49 | /* 50 | Input a hex number. Similar to getdec() 51 | */ 52 | gethex() 53 | {int digval,n; 54 | char *ptr; 55 | n=0; 56 | ptr=ccnbuff; 57 | putchar('$'); /* Prompt */ 58 | gets(ptr); 59 | while(*ptr==32)ptr++; 60 | while(*ptr) 61 | {digval=cchex(ptr++); 62 | if(digval==-1)break; 63 | n=digval+n*16;} 64 | return n;} 65 | /* 66 | Get char. from buffer. Check if hex. Return value or -1 67 | */ 68 | cchex(ptr) 69 | char *ptr; 70 | {char c; 71 | c=*ptr&127; 72 | if((c>='0')&(c<='9')) return c-'0'; 73 | if((c>='A')&(c<='F')) return c-55; 74 | if((c>='a')&(c<='f')) return c-87; 75 | return -1;} 76 | 77 | /* 78 | Output a byte in hex 79 | */ 80 | putbyte(byte) 81 | char byte; 82 | { char temp; 83 | temp=(byte>>4)&15; 84 | ccptnib(temp); 85 | temp=byte&15; 86 | ccptnib(temp);} 87 | 88 | /* 89 | Output nibble 90 | */ 91 | ccptnib(ch) 92 | char ch; 93 | { if(ch<10)putchar(ch+48); 94 | else putchar(ch+55);} 95 | 96 | /* 97 | Output a 16 bit hex number 98 | */ 99 | puthex(ptr) 100 | char *ptr; 101 | { char temp; 102 | temp=ptr>>8; 103 | putbyte(temp); 104 | temp=ptr; 105 | putbyte(temp);} 106 | 107 | /* 108 | Get a signed integer from a string in memory 109 | */ 110 | atoi(ptr) 111 | char *ptr; 112 | {int digval,sign,n; 113 | n=0; 114 | sign=1; 115 | while(*ptr==' ')ptr++; 116 | if(*ptr=='-'){sign=-1;ptr++;} 117 | while(*ptr) 118 | {digval=ccnum(ptr++); 119 | if(digval==-1)break; 120 | n=digval+n*10;} 121 | return n*sign;} 122 | 123 | /* 124 | Get hex value from string in memory 125 | */ 126 | hextoi(ptr) 127 | char *ptr; 128 | {int digval,n; 129 | n=0; 130 | while(*ptr==' ')ptr++; 131 | while(*ptr) 132 | {digval=cchex(ptr++); 133 | if(digval==-1)break; 134 | n=digval+n*16;} 135 | return n; 136 | } 137 | CONFG),A ;Mark as CON: 138 | JP ccsxt ;back with channel 1 in HL 139 | ; Set up g -------------------------------------------------------------------------------- /small_c_17/OPT.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/small_c_17/OPT.COM -------------------------------------------------------------------------------- /small_c_17/OPT.DOC: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | OPT: A Three Pass Optimiser for Small C 9 | 10 | 11 | Opt is a simple optimiser which improves the execution speed of the 12 | assembler output of the Z80 Small C compiler. It normally gives a net 13 | reduction in the size of the assembled program. 14 | 15 | To call the optimiser use a command of the form: 16 | 17 | opt filename 18 | 19 | Opt assumes that the file has the extension .ZSM and produces its output 20 | in FILENAME.OPT. Note that after optimisation FILENAME.ZSM contains the 21 | output of the second optimiser pass, not the original assembly language 22 | code. 23 | 24 | Using the optimiser on a variety of programs such as itself, the Z80 25 | Small C compiler and a number of utilities has been found to give an 26 | improvement in run time of 15-20%. The resulting programs are also 27 | slightly smaller. 28 | 29 | The following optimisations are applied. The left-hand column gives the 30 | original code, the optimised code is on the right. 31 | 32 | 33 | 1.1) Negative constant 34 | 35 | 36 | LD HL, LD HL,0- 37 | CALL ccneg 38 | 39 | 40 | This avoids a particular stupidity of the Small C compiler, which 41 | loads the absolute value of a negative constant and then negates it 42 | rather than using the assembler to do the negating. Saves 3 bytes. 43 | 44 | 45 | 46 | 1.2) Double constant 47 | 48 | 49 | LD HL, LD HL,2* 50 | ADD HL,HL 51 | 52 | 53 | A further stupidity of the assembler is that it calculates constant 54 | array offsets at run-time rather than at compile time. Here we use 55 | the assembler to do the sum for us. Saves 1 byte. 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | - 1 - 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 1.3) Push and pop around LD HL 75 | 76 | 77 | PUSH HL EX DE,HL 78 | LD HL, LD HL, 79 | POP DE 80 | 81 | 82 | The compiler tends to load everything through the HL register pair 83 | and get things into DE as an afterthought. The above example is 84 | better accomplished by exchanging the DE and HL registers. The 85 | previous contents of DE are lost in both the above fragments. Saves 86 | 1 byte. 87 | 88 | 89 | 90 | 1.4) Zero subscript 91 | 92 | 93 | EX DE,HL LD D,H 94 | LD HL,<0 or 2*0> LD E,L 95 | ADD HL,DE 96 | 97 | 98 | The above construct is frequently used to find the address of the 99 | first element of an array. There is no reason to suppose that the 100 | new contents of DE (the base address of the array) will ever be 101 | used, but I put them there anyway, just in case. Saves 3 bytes. 102 | 103 | 104 | 105 | 1.5) One subscript 106 | 107 | 108 | EX DE,HL LD D,H 109 | LD HL,1 LD E,L 110 | ADD HL,DE INC HL 111 | 112 | 113 | This construct is used to find the address of the second element of 114 | a character array (with a constant index 1). It's quicker just to 115 | increment the base address. Saves 2 bytes. 116 | 117 | 118 | 119 | 1.6) Two subscript 120 | 121 | 122 | EX DE,HL LD D,H 123 | LD HL,<2 or 2*1> LD E,L 124 | ADD HL,DE INC HL 125 | INC HL 126 | 127 | 128 | Constant subscripts of 2 are improved by the above substitution. 129 | Saves 1 byte. 130 | 131 | 132 | - 2 - 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 1.7) Fetch integer from top of stack 141 | 142 | 143 | LD HL,0 POP HL 144 | ADD HL,SP PUSH HL 145 | CALL ccgint 146 | 147 | 148 | Local variables in Small C are kept on the stack and fetched by 149 | adding an offset to the stack pointer to get an address from which 150 | the value is fetched. If the required variable is at the top of the 151 | stack it is quicker to pop it off. Note that this is the fastest 152 | way of fetching an integer, so the most frequently used variable in 153 | a routine should be the last one to be defined. Saves 5 bytes. 154 | 155 | 156 | 157 | 1.8) Fetch second top integer from stack 158 | 159 | 160 | LD HL,2 POP BC 161 | ADD HL,SP POP HL 162 | CALL ccgint PUSH HL 163 | PUSH BC 164 | 165 | 166 | This is similar to 1.7). The BC register does not seem to be used 167 | for much in the Small C compiler, so it's safe to trample all over 168 | it. Saves 3 bytes. 169 | 170 | 171 | 172 | 2.1) Double EX DE,HL 173 | 174 | 175 | EX DE,HL 176 | EX DE,HL 177 | 178 | 179 | Obvious, isn't it? Save 2 bytes 180 | 181 | 182 | 183 | 2.2) DE <- HL followed by EX DE,HL 184 | 185 | 186 | LD D,H LD D,H 187 | LD E,L LD E,L 188 | EX DE,HL 189 | 190 | 191 | If DE and HL contain the same thing there's no point in swapping 192 | them. Saves 1 byte. 193 | 194 | 195 | 196 | 197 | 198 | - 3 - 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 2.3) DE <- HL followed by LD HL 207 | 208 | 209 | LD D,H EX DE,HL 210 | LD E,L LD HL, 211 | LD HL, 212 | 213 | 214 | Loading DE from HL and then overwriting HL is the same as swapping 215 | DE and HL and overwriting HL. You still lose what used to be in DE. 216 | Saves 1 byte. 217 | 218 | 219 | 220 | 2.4) Expand ccpchar 221 | 222 | 223 | CALL ccpchar LD A,L 224 | LD (DE),A 225 | 226 | 227 | The run-time routine to store a character from HL to the address 228 | pointed to by DE is only two bytes long - shorter than a CALL to it. 229 | Saves 1 byte. 230 | 231 | 232 | 233 | 2.5) Expand ccgint to DE 234 | 235 | 236 | CALL ccgint LD E,(HL) 237 | EX DE,HL INC HL 238 | LD HL, LD D,(HL) 239 | LD HL, 240 | 241 | 242 | The run-time routine ccgint fetches the integer pointed to by HL and 243 | puts it in HL. If a call to ccgint if followed by a swap and load 244 | to HL it is equivalent to loading the integer pointed to by HL 245 | straight into DE. Saves 1 byte. 246 | 247 | 248 | 249 | 2.6) Expand ccgint 250 | 251 | 252 | CALL ccgint LD A,(HL) 253 | INC HL 254 | LD H,(HL) 255 | LD L,A 256 | 257 | 258 | The run-time routine ccgint on its own can be expanded to the above 259 | in-line code. Uses 1 extra byte. 260 | 261 | 262 | 263 | 264 | - 4 - 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 2.7) Expand ccpint 273 | 274 | 275 | CALL ccpint LD A,L 276 | LD (DE),A 277 | INC DE 278 | LD A,H 279 | LD (DE),A 280 | 281 | 282 | The run-time routine ccpint stores the integer in HL at the address 283 | in DE. This can be expanded to in-line code. Uses 2 extra bytes. 284 | 285 | 286 | 287 | 2.8) Expand ccgchar to DE 288 | 289 | 290 | CALL ccgchar LD A,(HL) 291 | EX DE,HL LD E,A 292 | LD HL, RLCA 293 | SBC A,A 294 | LD D,A 295 | LD HL, 296 | 297 | 298 | The run-time routine ccgchar fetches and sign extends into HL a 299 | character from the address pointed to by HL. If a call to ccgchar 300 | is follwed by a swap and load to HL it is equivalent to a load 301 | directly to DE. Uses 1 extra byte. 302 | 303 | 304 | 305 | 2.9) Expand ccgchar 306 | 307 | 308 | CALL ccgchar LD A,(HL) 309 | LD L,A 310 | RLCA 311 | SBC A,A 312 | LD H,A 313 | 314 | 315 | The run-time routine ccgchar on its own can be expanded to in-line 316 | code. Uses 2 extra bytes. 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | - 5 - 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 3.1) LD HL; EX: LD HL -> LD DE; LD HL 339 | 340 | 341 | LD HL, LD DE, 342 | EX DE,HL LD HL, 343 | LD HL, 344 | 345 | 346 | This another case where the compiler loads things into DE through 347 | HL. It's quicker to load directly into DE, unless is an 348 | explicit memory address. Saves 1 byte. 349 | 350 | 351 | 352 | 3.2) JZ around unconditional jump 353 | 354 | 355 | JP Z, JP NZ, 356 | JP where: 357 | where: 358 | 359 | 360 | A conditional jump around an unconditional jump is the same as a 361 | jump to the destination of the unconditional jump, but with the 362 | condition reversed. (The corresponding case for JNZ does not seem 363 | to occur in Small C output and is not tested for.) Saves 3 bytes. 364 | 365 | 366 | 367 | 3.3) Store followed by load 368 | 369 | 370 | LD , LD , 371 | LD , 372 | 373 | 374 | After storing in there is no need to load from . The 375 | number of bytes saved depends on the particular LD instructions. It 376 | is either one or three. For accounting purposes the optimiser 377 | program assumes a saving of 2 bytes. 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | - 6 - 397 |  -------------------------------------------------------------------------------- /small_c_17/STRING.LIB: -------------------------------------------------------------------------------- 1 | /* 2 | * STRING FUNCTIONS FOR SMALL C 3 | * BASED ON CORRESPONDING UNIX FUNCTIONS 4 | */ 5 | 6 | /* 7 | strlen( string ) 8 | char *string ; 9 | { 10 | int counter ; 11 | 12 | counter = 0 ; 13 | while( *string++ ) 14 | counter++ ; 15 | return counter ; 16 | } 17 | */ 18 | 19 | #asm 20 | strlen: 21 | POP HL 22 | POP BC 23 | PUSH BC 24 | PUSH HL 25 | LD HL,0 26 | ccstr3: 27 | LD A,(BC) 28 | OR A 29 | RET Z 30 | INC BC 31 | INC HL 32 | JP ccstr3 33 | #endasm 34 | 35 | 36 | 37 | /* 38 | strcpy( to, from ) 39 | char *to, *from ; 40 | { 41 | char *temp ; 42 | 43 | temp = to ; 44 | while( *to++ = *from++ ) ; 45 | return temp ; 46 | } 47 | */ 48 | 49 | #asm 50 | strcat: 51 | POP HL 52 | POP BC ;BC is from 53 | POP DE ;DE is to 54 | PUSH DE 55 | PUSH BC 56 | PUSH HL 57 | LD H,D ;return to 58 | LD L,E 59 | ccstr4: 60 | LD A,(DE) 61 | OR A 62 | INC DE 63 | JP NZ,ccstr4 64 | DEC DE 65 | ccstr5: 66 | LD A,(BC) 67 | LD (DE),A 68 | INC DE 69 | INC BC 70 | OR A 71 | RET Z 72 | JP ccstr5 73 | #endasm 74 | 75 | 76 | /* 77 | strcat( to, from ) 78 | char *to, *from ; 79 | { 80 | char *temp ; 81 | 82 | temp = to ; 83 | while( *to++ ) ; 84 | to-- ; 85 | while( *to++ = *from++ ) ; 86 | return temp ; 87 | } 88 | */ 89 | 90 | #asm 91 | strcmp: 92 | POP BC 93 | POP HL ;HL is s2 94 | POP DE ;DE is s1 95 | PUSH DE 96 | PUSH HL 97 | PUSH BC 98 | ccstr1: 99 | LD A,(DE) ;fetch *s1 100 | CP (HL) 101 | JP NZ,ccstr6 ;quit if *s1 != *s2 102 | OR A ;check *s1 for zero 103 | INC DE 104 | INC HL 105 | JP NZ,ccstr1 ;loop if *s1 != 0 106 | LD HL,0 107 | RET 108 | ccstr6: 109 | SUB (HL) 110 | JP ccsxt ;else return *s1-*s2 111 | #endasm 112 | 113 | 114 | 115 | /* 116 | strcmp( s1, s2 ) 117 | char *s1, *s2 ; 118 | { 119 | while( *s1 == *s2 ) { 120 | if( *s1 == 0 ) 121 | return 0 ; 122 | s1++ ; 123 | s2++ ; 124 | } 125 | return *s1 - *s2 ; 126 | } 127 | */ 128 | 129 | #asm 130 | strcpy: 131 | POP HL 132 | POP DE ;DE is from 133 | POP BC ;BC is to 134 | PUSH BC 135 | PUSH DE 136 | PUSH HL 137 | LD H,B ;return to 138 | LD L,C 139 | ccstr2: 140 | LD A,(DE) 141 | LD (BC),A 142 | INC DE 143 | INC BC 144 | OR A ;test char for zero 145 | JP NZ,ccstr2 146 | RET 147 | #endasm 148 |  -------------------------------------------------------------------------------- /small_c_17/USQ.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/small_c_17/USQ.COM -------------------------------------------------------------------------------- /small_c_17/WSCLEAN.C: -------------------------------------------------------------------------------- 1 | /* 2 | This program clears the top bit of the characters in text files. 3 | Just run it. The program will prompt for file names. 4 | */ 5 | #include crun2.lib 6 | #include conio2.lib 7 | #include file2.lib 8 | #define CZ 26 9 | char fibuf[20],fobuf[20]; 10 | main() 11 | { 12 | int ichan,ochan; 13 | char ch; 14 | puts("Give full input file name: "); 15 | gets(fibuf); 16 | if((ichan=fopen(fibuf,"r"))==0) 17 | {puts("\nProgram aborted\n\n");exit();} 18 | puts("\nGive full output file name: "); 19 | gets(fobuf); 20 | if((ochan=fopen(fobuf,"w"))==0) 21 | {puts("\File opening error.\n\n");exit();} 22 | while(1) 23 | { 24 | ch=getc(ichan); 25 | ch=ch&127; 26 | putc(ch,ochan); 27 | if(ch==CZ)break; 28 | } 29 | fclose(ochan);exit(); 30 | } 31 | file: "); 32 | gets(fname); 33 | crlf(); 34 | cptr=fname; 35 | } 36 | else cptr=argv[1]; 37 | while((ch=*cptr)==' ')cptr++; 38 | count=1; 39 | w -------------------------------------------------------------------------------- /small_c_17/WSCLEAN.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/small_c_17/WSCLEAN.COM -------------------------------------------------------------------------------- /small_c_17/ZSC-1.CQ: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/small_c_17/ZSC-1.CQ -------------------------------------------------------------------------------- /small_c_17/ZSC-2.CQ: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/small_c_17/ZSC-2.CQ -------------------------------------------------------------------------------- /small_c_17/ZSC.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/small_c_17/ZSC.COM -------------------------------------------------------------------------------- /small_c_17/ZSM.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelVis/mescc/c0a93d338be52215547ff622242563b9b1d9dd0f/small_c_17/ZSM.COM -------------------------------------------------------------------------------- /small_c_17/ZSM.DOC: -------------------------------------------------------------------------------- 1 | 2 | 3 | ZSM, a CP/M Z80 assembler. 4 | 5 | ZSM is an assembler for the Z80 microprocessor. It uses standard 6 | Zilog/Mostek mnemonics, supports conditional assembly and 7 | produces Intel HEX file suitable for loading with the CP/M LOAD 8 | utility. ZSM is a disk based assembler, i.e. source code is read 9 | from disk, the resulting object code is written to disk and an 10 | optional print file can be written to disk. Alternatively the 11 | print file can be redirected to the console. 12 | 13 | 1. Using the assembler. 14 | ----------------------- 15 | The assembler is initiated by typing: 16 | 17 | ZSM filename.pqr 18 | 19 | This takes the file 'filename.ZSM' and assembles it according to 20 | the parameters 'p','q' and 'r' and the options chosen. The 21 | parameters must be selected as follows: 22 | 23 | p - the disk drive containing the source code, 24 | 'filename.ZSM'. A to P or @ for default drive. 25 | 26 | q - the disk drive where the object code, 'filename.HEX' is 27 | to be written. A to P or @ for default drive, Z if not 28 | required. 29 | 30 | r - the disk drive where the listing is to be written, 31 | 'filename.PRN'. A to O or @ for default drive, P to 32 | the list device, X to the console, Y to the console 33 | with errors to the pinter, Z to suppress listing. 34 | 35 | For example assembling the file TEST.ZSM:- 36 | 37 | ZSM TEST.AAB 38 | 39 | This expects the file TEST.Z80 on drive A, will write the object 40 | code file, TEST.HEX to drive A and the listing file, TEST.PRN to 41 | drive B. 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 1 61 | 62 | 63 | 64 | 2. Assembler syntax 65 | ------------------- 66 | 2.1 ASSEMBLER MNEMONICS 67 | The assembler recognises all standard Z80 mnemonics as defined in 68 | the Z80 CPU Technical Manual. The following mnemonics are 69 | recognised in both forms shown. 70 | 71 | ADC A,s ADC s 72 | ADD A,n ADD n 73 | ADD A,r ADD r 74 | ADD a,(HL) ADD (HL) 75 | ADD a,(IX+d) ADD (IX+d) 76 | ADD a,(IY+d) ADD (IY+d) 77 | 78 | 2.2 LABELS 79 | Labels may be up to 11 characters long. The first character of 80 | the label must be alphabetic (i.e. A-Z) or '_' or '$'. A colon, 81 | ':' following the label is optional. 82 | 83 | 2.3 CONSTANTS 84 | ZSM allows binary, octal, decimal, hexadecimal and ASCII 85 | constants according to the following conventions: 86 | 87 | Binary - number formed from binary digits (0,1) and terminated by 88 | the character 'B'. Range 0000000000000000B to 1111111111111111B. 89 | 90 | Example: LD HL,10001111101101B 91 | 92 | Octal - number formed from octal digits (0-7) and terminated by 93 | the character 'Q'. Range 000000Q to 177777Q. 94 | 95 | Example: LD HL,23670Q 96 | 97 | Decimal - number formed from decimal digits (0-9) and EITHER left 98 | unterminated or terminated by the character 'D'. 99 | Range: 0 to 65535. 100 | 101 | Example: LD HL,32145 102 | 103 | Hexadecimal - number formed from hexadecimal digits (0-9 and A-F) 104 | and terminated by the character 'H'. A hex number beginning with 105 | a letter must be preceded by a 0 to distinguish it from a label 106 | or register name. Range 0000H to FFFFH. 107 | 108 | Example: LD HL,0A3FH 109 | 110 | ASCII - number formed from ASCII value of characters enclosed in 111 | single quotes. Range ' ' to '~' or 20H to 7EH including all 112 | alphanumerics and punctuation. 113 | 114 | Examples: LD HL,'Wk' 115 | LD A,'*' 116 | 117 | The $ sign used as a constant represents the current value of the 118 | program counter. 119 | 120 | 121 | 2 122 | 123 | 124 | 125 | 2.4 EXPRESSION EVALUATION 126 | Operands in instructions and pseudo-ops may consist of arithmetic 127 | expressions which are evaluated at assembly time and the 128 | calculated value used as part of the object code. The following 129 | operators may be used to form expressions: 130 | 131 | + Addition 132 | - Subtraction (or unary Negation) 133 | * Multiplication 134 | / Division 135 | .MOD. Modulus 136 | < or .GT. Greater Than. X.GT.Y true if X greater than Y. 137 | .GE. Greater than or Equal. X.GE.Y true if X 138 | greater than or equal to Y. 139 | > or .LT. Less Than. X.LT.Y true if X less than Y. 140 | .LE. Less than or Equal. X.LE.Y true if X less 141 | than or equal to Y. 142 | = or .EQ. Equal. X.EQ.Y true if X equals Y. 143 | .NE. Not Equal. X.NE.Y true if X not equal to Y. 144 | .SHL. n Shift Left n bits. 145 | .SHR. n Shift Right n bits. 146 | .NOT. Logical NOT (unary) 147 | .AND. Logical AND 148 | .OR. Logical OR 149 | .XOR. Logical Exclusive OR 150 | .LOW. Low byte of expression (.MOD. 256) 151 | .HIGH. High byte of expression (.SHR. 8) 152 | 153 | Expressions are evaluated left to right with no precedence. No 154 | parentheses can be used in expressions so some care is required 155 | to ensure that expressions are correctly formed. Unary 156 | expressions .NOT., .LOW. and .HIGH. must be at the beginning of 157 | an expression and only act on the next parameter in the 158 | expression. For example: 159 | 160 | DB .LOW. 1234H + 50 161 | 162 | is evaluated as (.LOW. 1234H) + 50, not .LOW.(1234H + 50). 163 | 164 | 165 | 2.5 PSEUDO-OPCODES 166 | 167 | DB or DEFB (define byte) 168 | The DB pseudo-op tells the assembler to reserve a byte or string 169 | of bytes with specific values. The bytes may be defined as 170 | constants, expressions as described earlier or as already defines 171 | symbols. 172 | 173 |