M100 Small-C 85 Lib
Willard Goosey
goosey@sdc.org
4/16/2017

HISTORY:
Someone did a Small-C runtime for the Model 100 a long time
ago. Unfortunately that version has vanished from the Internet. It's
closest surviving kin is a NEC8201 Small-C, which may or may not be on
web8201.

Meanwhile, Small-C has survived as a niche and perhaps even
prospered, with many different versions available for may different
machines. Small C-85 is one of these, specifically supporting the
Model 100's 8085 and its "undocumented" instructions. 

Like most people, I dreaded the thought of having to handle even a
subset of C's standard library on the Model 100, which is an awesome
little machine but does not in any way resemble a UNIX box.

Then one day I actually unarchived CPC-NEC.ZIP and actually looked at
how it supported stdio. And to my great surprise, it _didn't_! A
handful of functions like getc() and putc() were mapped directly to
ROM calls, and that was it.

And I thought, heck, I can do that! So here we are. 

Requirements:

Small-C 85 : https://github.com/ncb85/SmallC-85
ASxxxx : http://shop-pdp.net
hex2co : From Chris Osburn's personal library at club100.org
	http://club100.org/memfiles/index.php?&direction=0&order=&directory=Chris%20Osburn/RBASIC%20Support
GNU Make: Standard GNU util 
objcopy: Standard GNU binutil

Building:

Download and install all of the above. I suggest editing the SmallC-85
makefile to specify the directory for global include files as
something convenient.

This archive will be available at http://www.sdc.org/~goosey/m100 and
in my personal library at Club100.

a "make alllibs" will make the library and install it in ./lib. At
this point you should be good to Small-C!

Use:

Please refer to the scc8080 and ASX documention for the compiler,
assembler, and linker themselves. Refer to the M100 Technical
Reference, m100.def, and the Covington maps for ROM routine details.

The current makefile rules set, by default, the starting address of
the M100 binary at 0xF000. If your binary tries to load above MAXRAM,
the Model 100 will error out. To set a different load address,
redefine the variable DEF_ADDRESS in the makefile:

	prstar.ihx: DEF_ADDRESS=0xE800
	prstar.ihx: prstar.rel psuran.rel

Prstar.ihx will be linked to start at 0xE800.

By default, the linker creates a .map file that describes the final 
addresses of all global symbols, as well as all the "modules" linked
in. Examine this file to determine the uppermost address of your
binary.



WARNING:
The stack starts below HIMEM and grows downwards. There are currently
no checks to make sure it doesn't clobber files.

To compile hallo.c into hallo.co make(1) will:

scc8080 -u hallo.c
#the compiler itself
#-u use undocumented opcodes

as8085 -g -o hallo.rel hallo.s
#the assembler. 
#-l generate list file
#-g don't complain about unknown globals
#-o output file

aslink -n -i -m -b M100_CODE=0xF000 -o hallo.ihx lib/cstart.rel hallo.rel -l small.lib 
#linker
#-n = don't echo commands to stdout
#-i = hex file out
#-m = generate map file
#-b modname=address module modname starts at address
#-l library library file
#-o = output file

objcopy -I ihex -O ihex --gap-fill 0 hallo.ihx hallo.hex
#reformat the hex file into something hex2co can handle
#-I input format
#-O output format
#--gap-fill 0 fill any gaps in the output file with 0's.

hex2co hallo.hex
#generate the .co

Library Reference:

This makes no real attempt to be portable to other machines, rather it
maps the Model 100's ROM API directly to C function calls.

This supports the BASIC command CALL <address>,A,HL. the formal
arguements for main() are main(char A, int HL).

ROM calls directly callable: These take no arguements and return
nothing, so don't need wrapper functions. These are uppercase because
all symbols in m100.def are uppercase.

//LCD control
CRLF()	//print ^M^J
HOME()  //home cursor
CLS()	//clear screen
SETSYS()  //lock line 8
RSTSYS()  //unlock line 8
LOCK()	  //lock screen (no scrolling)
UNLOCK()  //unlock screen (enable scrolling)
CURSON()  //turn on text mode cursor
CUROFF()  //turn off text mode cursor
DELLIN()  //delete current line
INSLIN()  //insert line
ERAEOL()  //erase line from cursor to end of line
ENTREV()  //turn on  reverse video
EXTREV()  //turn off reverse video
DTLINE()  //print day/date/time as it appears on MENU

//function key support
CLRFLK()  //clear function key table
DSPFNK()  //display function keys
ERAFNK()  //erase function key display
FNKSB()   //display function key table if enabled
BK2SK()   //install BASIC function key table

//printer
PRTLCD()  //dump lcd to printer

//serial port
DISC()    //disconnect phone line
CONN()    //connect phone line
SENDCQ()  //send XON (^Q) to serial port
SENDCS()  //send XOFF (^S) to serial port
CLSCOM()  //deactivate rs232/modem

//cassette functions
CTON()   //turn on cassette motor
CTOFF()  //turn off cassette motor
SYNCW()  //write cassette header and sync byte
SYNCR()  //read cassette header and sync byte

//directory support
DIROK()  //sort directory

//other functions
INITIO()  //cold start
IOINIT()  //warm start
BOOT()    //reboot
TDDPT()   //print time on top line of screen
PFRE()    //print number of bytes of free memory
BEEP()    //BASIC BEEP

//ROM Apps. NO comeing back from these!
MENU()	  //jump to main menu
TXT()    //ROM text editor
BASIC()  //BASIC
TELCOM()  // telcom app
ADDRSS()  //
SCHEDL()  // address/schedule database ROM app

//ROM call wrapper functions:

int getc()
int getchar()
	//blocking, echoing read 1 char from keyboard

int chget()
	//blocking noechoing read 1 char from keyboard

char *gets()      
	//line input, returns system input buffer

putc(char c)
	//write one char to LCD

putd(int i)
	//write an integer to LCD

puts(char *s)
	//write a string to LCD

plot(int x,int y)
	//set dot x,y

unplot(int x,int y) 
	//clear dot x,y

char *time(char *s)
	//return current time in s

char *date(char *s)
	//return current date in s

chr *day(char *s)
	//return day name in s

int kyread()
	//non-blocking non-echoing keyboard read

esca(char c)
	//print escape code <esc>-c to LCD
	//note esccode.h

barpos(int i)
	//locate bar cursor on location i (0-23)

barcur(int i)
	//toggle bar cursor to opposite state i=loc 0-23

int keywaitu()
	//blocking keyboard input, uppercases result

int chsns()
	//check keyboard queue for characters
	//return 1 if key pending
	//return 0 if no keys pending

int keyx()
	//check keyboard queue for chars or <break>
	//returns : 0 on keyboard queue empty
	// 1 on keys pending
	// 0xFFFF on break pressed

int brkchk()
	//check for break or pause only
	//return 1 if <break> or <pause> pressed
	//return 0 otherwise

stfnk(char *s)  //(UNTESTED)
	//set function key table from s 

stdspf(char *s)	// (UNTESTED)
	//set and display function key table from *s

int printr(char c)  // (UNTESTED)
	//print char c on printer, returns -1 on error 

pnotab(char c) //(UNTESTED)
	//print char c on printer, do not expand tab	

prttab(char c) //(UNTESTED)
	//print char c on printer, expand tab to spaces

dial(char *s)  // (UNTESTED)
	//dial phone number pointed to by char *s

int rcvx() // (UNTESTED)
	//return number of chars in rs232 recieve queue

int rv232c()  // (UNTESTED)
	//return char from rs232 queue 
	//-1 on error -2 on BREAK

sd232c(char c)   // (UNTESTED)
	//send c out serial port with soft flow control

sndcom(char c)   // (UNTESTED)
	//send c out serial port with no soft flow control

int cardet()    // (UNTESTED)
	//returns 1 if built-in modem has carrier

baudst(char c)  // (UNTESTED)
	//set rs232 or modem baud rate
	//c= '1'..'9','M'

inzcom(int i,char baud,char config)  // (UNTESTED)
	//initialize serial port or modem 
	//i=1 for rs232, 0 for modem
	//c1=baud rate '1'..'9','M'
	//c2=config

setser(int flag,char *s)     //(UNTESTED)
	//set serial config and init rs232 or modem
	//flag=1 for rs232, 0 for modem
	//s=STAT block, 5 bytes null terminated

prsnam(char *s,int i)  //(UNTESTED)
	//parse a file.do filename into FILNAM system var
	//as "FILE  DO"
	//s=filename
	//i=length of filename

maktxt(int i[])   //(UNTESTED)
	//create text file. prsnam() must be called first
	//i[0]=top of new file
	//i[1]=address of directory entry
	//i[2]=1 if file existed, 0 if new file

char *chkdc(char *s) //(UNTESTED)
	//search for a 4.2 filename
	//returns address of file or 0 if no file found

char *fndfil()	//(UNTESTED)
	//search for a file in directory
	//prsnam() must be called first
	//returns address of dir entry on file found
	//returns 0 on no file found

char *chkfn(char *s)	//(UNTESTED)
	//search for 6.2 file
	//returns address of file or 0 if no file found

char *mkpnam(char *s0, char *s1)  //(UNTESTED)
	//convert directory entry style name FILE  DO into
	//6.2 format FILE.DO stored in s1 (null terminated) 
	//s1 assumed to be at least 10 chars long
	//returns s1

char *gtxttb(char *s)    //(UNTESTED)
	//gets top address of a file 
	//s=directory entry
	//returns address of top of file

kilasc(char *top,char *dir)  //(UNTESTED)
	//delete text file  
	//top=address of top of file
	//dir=address of directory entry
 
int inschr(char c, char *s)   //(UNTESTED)
	//insert a character in a file 
	//c=char to insert
	//s=address to insert at
	//returns 0 on success
	//returns -1 on out of memory

int makhol(int i,char *s)   //(UNTESTED)
	//insert a number of spaces
	//i=number of spaces
	//s=address to insert at
	//returns 0 on success -1 on memory full

masdel(int i,char *s)   //(UNTESTED)
	//delete a number of characters 
	//i=number of spaces
	//s=address to delete from

char *nxtdir(char *s)	//(UNTESTED)
	//retrieve the next directory entry of an active file
	//s=dir entry before starting point
	//returns pointer to dir entry on success or 0 on fail


char *FREDIR() //(UNTESTED)	
	//locates an empty directory slot
	//returns pointer to dir slot

music(int freq, unsigned char dur)
	//generates a tone
	//note sound.h

char *prgadd(char *filename) //(UNTESTED)
	//return address of program


//other functions: 

//Thanks to Daryl Tester for these!
hex4(int i) 
	//print 1 hex digit

hex8(int i) 
	//print 2 hex digit

hex16(int i) 
	//print 4 hex digit

//Functions from SmallC-85

int abs(int num)
      // return absolute value 

int atoi(char s[])
	//convert string s to int


#include <stdio.h>
int binary(char *word, int table[], int n)
	//binary search for string word in table[0] .. table[n-1]
        //reference CPL pg. 125

int isalpha(c) char c;
	// return true if C alphabetic

int isupper(c) char c;
	//return true if c uppercase

int islower(c) char c;
	//return true if c lowercase

int isdigit(c) char c;
	//return true if c is a digit

int isspace(c) char c;
	//return true if c is whitespace

int toupper(c) char c;
	//return uppercase of c

int tolower(c) char c
	//return lowercase of c

#include <stdio.h>
#define EOS 0
int index(char s[], char t[])
	//index - find index of string t in s
	//reference CPL 67.

char *itoa(int n,char s[])
	//return character string of int n

srand(int x)
	//seed rng

int rand()
	//16-bit RND

char *reverse(char *s)
	// Reverse a character string, reference CPL p 59

shellsort(int v[], int n)
	//Shell sort of string v[0] .... v[n-1] into increasing
	//order.
	//Reference CPL pg. 108.
 
char *strcat(char *s1, char *s2)
	//Concatenate s2 on the end of s1.  
	//S1's space must be large enough.
	//Return s1.

int strcmp(char *s1, char *s2)
	//Compare strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0

char *strcpy(char *s1, char *s2)
	//Copy string s2 to s1.  s1 must be large enough.
	//return s1

int strlen(char *s)
	//return length of string, reference CPL p 36 */

char *strncat(char *s1, char *s2, int n)
	//Concatenate s2 on the end of s1.  
	//S1's space must be large enough.
	//At most n characters are moved.
	//Return s1.

int strncmp(char *s1, char *s2, int n)
	//Compare strings (at most n bytes):  
	//s1>s2: >0  s1==s2: 0  s1<s2: <0

char *strncpy(char *s1, char *s2, int n)
	//Copy s2 to s1, truncating or null-padding to always copy n bytes
	//return s1


System Variable Reference:

small.lib makes a large number of system variables inherited from
m100.def available. These are named and described in m100vars.h


Version history:


0.0.1	Initial release
0.0.2	Bug fixes, reorganization, added sound.h, better docs


