mirror of
				https://github.com/deater/dos33fsprogs.git
				synced 2025-10-31 09:16:03 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1829 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1829 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| #include <SDL.h>
 | |
| 
 | |
| #include "gr-sim.h"
 | |
| #include "tfv_zp.h"
 | |
| #include "6502_emulate.h"
 | |
| 
 | |
| #include "apple2_font.h"
 | |
| 
 | |
| /* 280x192 hi-res mode	*/
 | |
| #define HGR_XSIZE	280
 | |
| #define HGR_YSIZE	192
 | |
| #define HGR_X_SCALE	2
 | |
| #define HGR_Y_SCALE	2
 | |
| 
 | |
| /* 40x48 low-res mode	*/
 | |
| #define GR_XSIZE	40
 | |
| #define GR_YSIZE	48
 | |
| #define GR_X_SCALE	14
 | |
| #define GR_Y_SCALE	8
 | |
| 
 | |
| /* 40 column only for now */
 | |
| #define TEXT_XSIZE	40
 | |
| #define TEXT_YSIZE	24
 | |
| #define TEXT_X_SCALE	14
 | |
| #define TEXT_Y_SCALE	16
 | |
| 
 | |
| static int xsize=GR_XSIZE*GR_X_SCALE;
 | |
| static int ysize=GR_YSIZE*GR_Y_SCALE;
 | |
| 
 | |
| static int debug=0;
 | |
| 
 | |
| /* Zero page addresses */
 | |
| #define WNDLFT	0x20
 | |
| #define WNDWDTH	0x21
 | |
| #define WNDTOP	0x22
 | |
| #define WNDBTM	0x23
 | |
| #define	CH	0x24
 | |
| #define CV	0x25
 | |
| #define GBASL	0x26
 | |
| #define GBASH	0x27
 | |
| #define BASL	0x28
 | |
| #define BASH	0x29
 | |
| #define	BAS2L	0x2A
 | |
| #define BAS2H	0x2B
 | |
| #define H2	0x2C
 | |
| #define V2	0x2D
 | |
| #define MASK	0x2E
 | |
| #define COLOR	0x30
 | |
| #define INVFLG	0x32
 | |
| #define YSAV	0x34
 | |
| #define YSAV1	0x35
 | |
| #define CSWL	0x36
 | |
| #define CSWH	0x37
 | |
| #define FIRST	0xF0
 | |
| #define SPEEDZ	0xF1
 | |
| #define FLASH	0xF3
 | |
| #define TEMP	0xFA
 | |
| 
 | |
| static int text_mode=0xff;
 | |
| static int text_page_1=0x00;
 | |
| static int hires_on=0x00;
 | |
| static int mixed_graphics=0xff;
 | |
| 
 | |
| static int plaid_mode=0;
 | |
| 
 | |
| void set_plaid(void) {
 | |
| 	plaid_mode=1;
 | |
| }
 | |
| 
 | |
| void clear_plaid(void) {
 | |
| 	plaid_mode=0;
 | |
| }
 | |
| 
 | |
| void soft_switch(unsigned short address) {
 | |
| 
 | |
| 	switch(address) {
 | |
| 		case TXTCLR:	// $c050
 | |
| 			text_mode=0x00;
 | |
| 			break;
 | |
| 		case TXTSET:	// $c051
 | |
| 			text_mode=0xff;
 | |
| 			break;
 | |
| 		case MIXCLR:	// $c052
 | |
| 			mixed_graphics=0x00;
 | |
| 			break;
 | |
| 		case MIXSET:	// $c053
 | |
| 			mixed_graphics=0xff;
 | |
| 			break;
 | |
| 		case LOWSCR:	// $c054
 | |
| 			text_page_1=0x00;
 | |
| 			break;
 | |
| 		case HISCR:	// $c055
 | |
| 			text_page_1=0xff;
 | |
| 			break;
 | |
| 		case LORES:	// $c056
 | |
| 			hires_on=0x00;
 | |
| 			break;
 | |
| 		case HIRES:	// $c057
 | |
| 			hires_on=0xff;
 | |
| 			break;
 | |
| 		default:
 | |
| 			fprintf(stderr,"Unknown soft switch %x\n",address);
 | |
| 			break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int soft_switch_read(unsigned short address) {
 | |
| 
 | |
| 	switch(address) {
 | |
| 		case TEXT_RD:	// $c01a
 | |
| 			return text_mode;
 | |
| 		case MIXED_RD:	// $c01b
 | |
| 			return mixed_graphics;
 | |
| 		case PAGE2_RD:	// $c01c
 | |
| 			return text_page_1;
 | |
| 		case HIRES_RD:	// $c01d
 | |
| 			return hires_on;
 | |
| 		default:
 | |
| 			fprintf(stderr,"Unknown soft switch read %x\n",address);
 | |
| 			break;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static SDL_Surface *sdl_screen=NULL;
 | |
| 
 | |
| int grsim_input(void) {
 | |
| 
 | |
| 	SDL_Event event;
 | |
| 	int keypressed;
 | |
| 
 | |
| 
 | |
| 	while ( SDL_PollEvent(&event)) {
 | |
| 
 | |
| 		switch(event.type) {
 | |
| 
 | |
| 		case SDL_KEYDOWN:
 | |
| 			keypressed=event.key.keysym.sym;
 | |
| 			switch (keypressed) {
 | |
| 
 | |
| 			case SDLK_ESCAPE:
 | |
| 				return 27;
 | |
| 			case 'a'...'z':
 | |
| 			case 'A'...'Z':
 | |
| 				return keypressed;
 | |
| 			case SDLK_UP:
 | |
| 				return 11;
 | |
| 			case SDLK_DOWN:
 | |
| 				return 10;
 | |
| 			case SDLK_RIGHT:
 | |
| 				return 21;
 | |
| 			case SDLK_LEFT:
 | |
| 				return 8;
 | |
| 			default:
 | |
| 				printf("Unknown %d\n",keypressed);
 | |
| 				return keypressed;
 | |
| 			}
 | |
| 			break;
 | |
| 
 | |
| 
 | |
| 		case SDL_JOYBUTTONDOWN:
 | |
| 		case SDL_JOYAXISMOTION:
 | |
| 			printf("Joystick!\n");
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			printf("Unknown input action!\n");
 | |
| 			break;
 | |
| 
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static unsigned int color[16]={
 | |
| 	0,		/*  0 black */
 | |
| 	0xe31e60,	/*  1 magenta */
 | |
| 	0x604ebd,	/*  2 dark blue */
 | |
| 	0xff44fd,	/*  3 purple */
 | |
| 	0x00a360,	/*  4 dark green */
 | |
| 	0x9c9c9c,	/*  5 grey 1 */
 | |
| 	0x14cffd,	/*  6 medium blue */
 | |
| 	0xd0c3ff,	/*  7 light blue */
 | |
| 	0x607203,	/*  8 brown */
 | |
| 	0xff6a3c,	/*  9 orange */
 | |
| 	0x9d9d9d,	/* 10 grey 2 */
 | |
| 	0xffa0d0,	/* 11 pink */
 | |
| 	0x14f53c,	/* 12 bright green */
 | |
| 	0xd0dd8d,	/* 13 yellow */
 | |
| 	0x72ffd0,	/* 14 aqua */
 | |
| 	0xffffff,	/* 15 white */
 | |
| };
 | |
| 
 | |
| static unsigned int hcolor[8]={
 | |
| 	0,		/*  0 black */
 | |
| 	0x2ad600,
 | |
| //	0x14f53c,	/*  1 bright green */
 | |
| //	0xff44fd,	/*  2 purple */
 | |
| 	0xc530ff,
 | |
| 	0xffffff,	/*  3 white */
 | |
| 	0,		/*  4 black */
 | |
| 	0xff6a3c,	/*  5 orange */
 | |
| 	0x14cffd,	/*  6 medium blue */
 | |
| 	0xffffff,	/*  7 white */
 | |
| };
 | |
| 
 | |
| static unsigned int hcolor_hack[8][2]={
 | |
| 	{0,0},		// 0000 KK
 | |
| 	{0,0},		// 0010 KK
 | |
| 	{1,1},		// 0100 OO
 | |
| 	{1,3},		// 0110 OW
 | |
| 	{2,0},		// 1000 BK
 | |
| 	{2,2},		// 1010 BB
 | |
| 	{3,3},		// 1100 WW
 | |
| 	{3,3},		// 1110 WW
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| 	/* a = ycoord */
 | |
| static int gbascalc(unsigned char a) {
 | |
| 
 | |
| 	unsigned char s,c;
 | |
| 
 | |
| 			/* input ABCD EFGH */
 | |
| 	s=a;		/* store a on stack */
 | |
| 	c=a&1;
 | |
| 	a=a>>1;		/* lsr */
 | |
| 	a=a&0x3;	/* mask */
 | |
| 	a=a|0x4;	/* 00001FG */
 | |
| 	ram[GBASH]=a;
 | |
| 	a=s;
 | |
| 
 | |
| 	a=a&0x18;	/* 000D E000 */
 | |
| 
 | |
| 	/* if odd */
 | |
| 	if (c) {
 | |
| 		a=a+0x7f+1;
 | |
| 	}
 | |
| 	ram[GBASL]=a;
 | |
| 	a=a<<2;
 | |
| 	a=a|ram[GBASL];
 | |
| 	ram[GBASL]=a;
 | |
| 
 | |
| 	if (debug) printf("GBAS=%02X%02X\n",ram[GBASH],ram[GBASL]);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int scrn(unsigned char xcoord, unsigned char ycoord) {
 | |
| 
 | |
| 	unsigned char a,y,c;
 | |
| 
 | |
| 	a=ycoord;
 | |
| 	y=xcoord;
 | |
| 
 | |
| 	c=a&1;
 | |
| 	a=a>>1;
 | |
| 	gbascalc(a);
 | |
| 	a=ram[y_indirect(GBASL,y)];
 | |
| 
 | |
| 	if (c) {
 | |
| 		return a>>4;
 | |
| 	}
 | |
| 	else {
 | |
| 		return a&0xf;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int scrn_page(unsigned char xcoord, unsigned char ycoord, int page) {
 | |
| 
 | |
| 	unsigned char a,y,c;
 | |
| 
 | |
| 	a=ycoord;
 | |
| 	y=xcoord;
 | |
| 
 | |
| 	c=a&1;
 | |
| 	a=a>>1;
 | |
| 	gbascalc(a);
 | |
| 	ram[GBASH]+=page;
 | |
| 	a=ram[y_indirect(GBASL,y)];
 | |
| 
 | |
| 	if (c) {
 | |
| 		return a>>4;
 | |
| 	}
 | |
| 	else {
 | |
| 		return a&0xf;
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static short gr_addr_lookup[24]={
 | |
| 	0x400,0x480,0x500,0x580,0x600,0x680,0x700,0x780,
 | |
| 	0x428,0x4a8,0x528,0x5a8,0x628,0x6a8,0x728,0x7a8,
 | |
| 	0x450,0x4d0,0x550,0x5d0,0x650,0x6d0,0x750,0x7d0,
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| static void draw_lowres(unsigned int *out_pointer,int gr_start, int gr_end) {
 | |
| 
 | |
| 	int i,j,yy,xx;
 | |
| 	int gr_addr,gr_addr_hi;
 | |
| 	int temp_col;
 | |
| 	unsigned int *t_pointer;
 | |
| 
 | |
| 	t_pointer=out_pointer+(gr_start*40*GR_X_SCALE*GR_Y_SCALE);
 | |
| 
 | |
| 	/* do the top 40/48 if in graphics mode */
 | |
| 	for(yy=gr_start;yy<gr_end;yy++) {
 | |
| 
 | |
| 		for(j=0;j<GR_Y_SCALE;j++) {
 | |
| 
 | |
| 			gr_addr=gr_addr_lookup[yy/2];
 | |
| 			gr_addr_hi=yy%2;
 | |
| 
 | |
| 			/* adjust for page */
 | |
| 			if (text_page_1) {
 | |
| 				gr_addr+=0x400;
 | |
| 			}
 | |
| 
 | |
| 			for(xx=0;xx<GR_XSIZE;xx++) {
 | |
| 
 | |
| 				if (gr_addr_hi) {
 | |
| 					temp_col=(ram[gr_addr]&0xf0)>>4;
 | |
| 				}
 | |
| 				else {
 | |
| 					temp_col=ram[gr_addr]&0x0f;
 | |
| 				}
 | |
| 
 | |
| 				for(i=0;i<GR_X_SCALE;i++) {
 | |
| 					*t_pointer=color[temp_col];
 | |
| 					t_pointer++;
 | |
| 				}
 | |
| 				gr_addr++;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void draw_text(unsigned int *out_pointer,int text_start, int text_end) {
 | |
| 
 | |
| 	int bit_set,ch,inverse,flash;
 | |
| 	int gr_addr;
 | |
| 	int xx,yy,i,j;
 | |
| 	unsigned int *t_pointer;
 | |
| 
 | |
| 	t_pointer=out_pointer+(text_start*40*TEXT_Y_SCALE*TEXT_X_SCALE);
 | |
| 
 | |
| 	for(yy=text_start;yy<text_end;yy++) {
 | |
| 		for(j=0;j<TEXT_Y_SCALE;j++) {
 | |
| 			for(xx=0;xx<TEXT_XSIZE;xx++) {
 | |
| 
 | |
| 				gr_addr=gr_addr_lookup[yy];
 | |
| 
 | |
| 				/* adjust for page */
 | |
| 				if (text_page_1) {
 | |
| 					gr_addr+=0x400;
 | |
| 				}
 | |
| 
 | |
| 				ch=ram[gr_addr+xx];
 | |
| 
 | |
| 				if (ch&0x80) {
 | |
| 					flash=0;
 | |
| 					inverse=0;
 | |
| 					ch=ch&0x7f;
 | |
| 				}
 | |
| 				else if (ch&0x40) {
 | |
| 					flash=1;
 | |
| 					inverse=0;
 | |
| 					ch=ch&0x3f;
 | |
| 				}
 | |
| 				else {
 | |
| 					inverse=1;
 | |
| 					flash=0;
 | |
| 					ch=ch&0x3f;
 | |
| 				}
 | |
| 
 | |
| 				for(i=0;i<TEXT_X_SCALE;i++) {
 | |
| 
 | |
| 		/* 14 x 16 */
 | |
| 		/* but font is 5x7 */
 | |
| 
 | |
| 		if (j>13) bit_set=0;
 | |
| 		else if (i>11) bit_set=0;
 | |
| 		else bit_set=(a2_font[ch][j/2])&(1<<(5-(i/2)));
 | |
| 
 | |
| 		if (inverse) {
 | |
| 			if (bit_set) *t_pointer=color[0];
 | |
| 			else *t_pointer=color[15];
 | |
| 		}
 | |
| 		else if (flash) {
 | |
| 			if (bit_set) *t_pointer=color[9];
 | |
| 			else *t_pointer=color[0];
 | |
| 		}
 | |
| 		else {
 | |
| 			if (bit_set) *t_pointer=color[15];
 | |
| 			else *t_pointer=color[0];
 | |
| 		}
 | |
| 
 | |
| 		t_pointer++;
 | |
| 
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void draw_hires(unsigned int *out_pointer,int y_start, int y_end) {
 | |
| 
 | |
| 	int i,j,yy,xx;
 | |
| 	int gr_addr;
 | |
| 	int temp_col;
 | |
| 	unsigned int *t_pointer;
 | |
| 	int last_last_pixel,last_pixel,current_byte,current_pixel,odd=0;
 | |
| 	int old_high=0,current_high=0;
 | |
| 
 | |
| 	t_pointer=out_pointer+(y_start*280*HGR_X_SCALE*HGR_Y_SCALE);
 | |
| 
 | |
| 	/* do the hires graphics */
 | |
| 	for(yy=y_start;yy<y_end;yy++) {
 | |
| 
 | |
| 		for(j=0;j<HGR_Y_SCALE;j++) {
 | |
| 
 | |
| 			gr_addr=gr_addr_lookup[yy/8]+0x1c00;
 | |
| 			gr_addr+=0x400*(yy&0x7);
 | |
| 
 | |
| 			/* adjust for page */
 | |
| 			if (text_page_1) {
 | |
| 				gr_addr+=0x2000;
 | |
| 			}
 | |
| 			last_pixel=0;
 | |
| 			last_last_pixel=0;
 | |
| 			odd=0;
 | |
| 
 | |
| 			for(xx=0;xx<HGR_XSIZE/7;xx++) {
 | |
| //				printf("HGR ADDR=%x\n",gr_addr);
 | |
| 				current_byte=ram[gr_addr];
 | |
| 
 | |
| 
 | |
| // BBBBBBBB     OOOOOOOO   OO?WW?BB  BB?KK?OO
 | |
| // 10101010     01010101   01011010  10100101
 | |
| // 1 1 010101   1 0 101010
 | |
| // d5           aa         
 | |
| 
 | |
| 
 | |
| 				for(i=0;i<7;i++) {
 | |
| 					old_high=current_high;
 | |
| 					current_high=!!(current_byte&0x80);
 | |
| 					current_pixel=!!(current_byte&(1<<i));
 | |
| 
 | |
| 					if (!odd) {
 | |
| 					int pattern;
 | |
| 					pattern=last_last_pixel<<2 |
 | |
| 						last_pixel<<1|
 | |
| 						current_pixel;
 | |
| 
 | |
| 					temp_col=(old_high<<2)|
 | |
| 						hcolor_hack[pattern][0];
 | |
| 
 | |
| //					printf("Temp col=%d\n",temp_col);
 | |
| //					for(k=0;k<HGR_X_SCALE;k++) {
 | |
| 
 | |
| 					*t_pointer=hcolor[temp_col];
 | |
| 					t_pointer++;
 | |
| 					*t_pointer=hcolor[temp_col];
 | |
| 					t_pointer++;
 | |
| 
 | |
| 					temp_col=(current_high<<2)|
 | |
| 						hcolor_hack[pattern][1];
 | |
| 
 | |
| 					*t_pointer=hcolor[temp_col];
 | |
| 					t_pointer++;
 | |
| 					*t_pointer=hcolor[temp_col];
 | |
| 					t_pointer++;
 | |
| 					}
 | |
| 					odd=!odd;
 | |
| 					last_last_pixel=last_pixel;
 | |
| 					last_pixel=current_pixel;
 | |
| 				}
 | |
| 
 | |
| 				gr_addr++;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| int grsim_update(void) {
 | |
| 
 | |
| 	unsigned int *t_pointer;
 | |
| 
 | |
| 	/* point to SDL output pixels */
 | |
| 	t_pointer=((Uint32 *)sdl_screen->pixels);
 | |
| 
 | |
| 	/* get the proper modes */
 | |
| 
 | |
| 	if (plaid_mode) {
 | |
| 		draw_text(t_pointer,0,6);
 | |
| 		draw_hires(t_pointer,48,112);
 | |
| 		draw_lowres(t_pointer,28,48);
 | |
| 	} else if (text_mode) {
 | |
| 		draw_text(t_pointer,0,TEXT_YSIZE);
 | |
| 	}
 | |
| 	else {
 | |
| 		if (hires_on) {
 | |
| 			draw_hires(t_pointer,0,192);
 | |
| 		}
 | |
| 		else {
 | |
| 			draw_lowres(t_pointer,0,48);
 | |
| 		}
 | |
| 
 | |
| 		if (mixed_graphics) {
 | |
| 			draw_text(t_pointer,20,TEXT_YSIZE);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	SDL_UpdateRect(sdl_screen, 0, 0, xsize, ysize);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| void setnorm(void) {
 | |
| 
 | |
| 	y=0xff;
 | |
| 	ram[INVFLG]=y;
 | |
| 
 | |
| }
 | |
| 
 | |
| int grsim_init(void) {
 | |
| 
 | |
| 	int mode;
 | |
| 	int x;
 | |
| 
 | |
| 	mode=SDL_SWSURFACE|SDL_HWPALETTE|SDL_HWSURFACE;
 | |
| 
 | |
| 	if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
 | |
| 		fprintf(stderr,
 | |
| 			"Couldn't initialize SDL: %s\n", SDL_GetError());
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	/* Clean up on exit */
 | |
| 	atexit(SDL_Quit);
 | |
| 
 | |
| 	/* assume 32-bit color */
 | |
| 	sdl_screen = SDL_SetVideoMode(xsize, ysize, 32, mode);
 | |
| 
 | |
| 	if ( sdl_screen == NULL ) {
 | |
| 		fprintf(stderr, "ERROR!  Couldn't set %dx%d video mode: %s\n",
 | |
| 			xsize,ysize,SDL_GetError());
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
 | |
| 
 | |
| 	/* Init screen */
 | |
| 	for(x=0x400;x<0x800;x++) ram[x]=0;
 | |
| 
 | |
| 	/* Set up some zero page values */
 | |
| 	ram[WNDLFT]=0x00;
 | |
| 	ram[WNDWDTH]=0x28;
 | |
| 	ram[WNDTOP]=0x00;
 | |
| 	ram[WNDBTM]=0x18;
 | |
| 
 | |
| 	a=0; y=0; x=0;
 | |
| 
 | |
| 	//FA62 RESET
 | |
| 
 | |
| 	setnorm();
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int color_equals(int new_color) {
 | |
| 
 | |
| 	/* Top and Bottom both have color */
 | |
| 	ram[COLOR]=((new_color%16)<<4)|(new_color%16);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| static void monitor_plot(void) {
 | |
| 
 | |
| 	unsigned char c;
 | |
| 
 | |
| 	/* Call into Monitor $F800 */
 | |
| 
 | |
| 	c=a&1;	/* save LSB in carry	*/
 | |
| 	a=a>>1;	/* lsr A */
 | |
| 	gbascalc(a);
 | |
| 
 | |
| 	if (c) {
 | |
| 		/* If odd, mask is 0xf0 */
 | |
| 		ram[MASK]=0xf0;
 | |
| 	}
 | |
| 	else {
 | |
| 		/* If even, mask is 0x0f */
 | |
| 		ram[MASK]=0x0f;
 | |
| 	}
 | |
| 
 | |
| 	a=ram[y_indirect(GBASL,y)];
 | |
| 
 | |
| 	a=a^ram[COLOR];
 | |
| 
 | |
| 	a=a&ram[MASK];
 | |
| 
 | |
| 	a=a^ram[y_indirect(GBASL,y)];
 | |
| 
 | |
| 	ram[y_indirect(GBASL,y)]=a;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| int basic_plot(unsigned char xcoord, unsigned char ycoord) {
 | |
| 
 | |
| 	if (ycoord>47) {
 | |
| 		printf("Y too big %d\n",ycoord);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	/* Applesoft Source Code	*/
 | |
| 	/* F225	GET X,Y Values		*/
 | |
| 	/* Y-coord in A			*/
 | |
| 	/* X-coord in Y			*/
 | |
| 	/* Check that X-coord<40	*/
 | |
| 	a=ycoord;
 | |
| 	y=xcoord;
 | |
| 
 | |
| 	if (y>=40) {
 | |
| 		printf("X too big %d\n",y);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	monitor_plot();
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| int basic_hlin(int x1, int x2, int at) {
 | |
| 
 | |
| 	int i;
 | |
| 
 | |
| 	for(i=x1;i<=x2;i++) basic_plot(i,at);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| static void bascalc(void) {
 | |
| 	// FBC1
 | |
| 
 | |
| 	unsigned char s,c;
 | |
| 
 | |
| 	s=a;
 | |
| 	c=a&0x1;
 | |
| 
 | |
| 	a=a>>1;
 | |
| 	a=a&0x3;
 | |
| 	a=a|0x4;
 | |
| 	ram[BASH]=a;
 | |
| 	a=s;
 | |
| 	a=a&0x18;
 | |
| 	if (c!=0) {
 | |
| 		a=a+0x80;
 | |
| 	}
 | |
| // BSCLC2
 | |
| 	ram[BASL]=a;
 | |
| 	a=a<<2;
 | |
| 	a=a|ram[BASL];
 | |
| 	ram[BASL]=a;
 | |
| 
 | |
| }
 | |
| 
 | |
| static void vtabz(void) {
 | |
| 
 | |
| 	bascalc();
 | |
| 
 | |
| 	a+=ram[WNDLFT];
 | |
| 	ram[BASL]=a;
 | |
| 
 | |
| }
 | |
| 
 | |
| static void rom_vtab(void) {
 | |
| 	/* fb5b */
 | |
| 	a=ram[CV];
 | |
| 	vtabz();
 | |
| }
 | |
| 
 | |
| static void setwnd(void) {
 | |
| 
 | |
| 	ram[WNDTOP]=a;
 | |
| 	a=0x0;
 | |
| 	ram[WNDLFT]=a;
 | |
| 	a=0x28;
 | |
| 	ram[WNDWDTH]=a;
 | |
| 	a=0x18;
 | |
| 	ram[WNDBTM]=a;
 | |
| 	a=0x17;
 | |
| // TABV
 | |
| 	ram[CV]=a;
 | |
| 	rom_vtab();
 | |
| }
 | |
| 
 | |
| static void vline(void) {
 | |
| 
 | |
| 	unsigned char s;
 | |
| 
 | |
| 	// f828
 | |
| vline_loop:
 | |
| 	s=a;
 | |
| 	monitor_plot();
 | |
| 	a=s;
 | |
| 	if (a<ram[V2]) {
 | |
| 		a++;
 | |
| 		goto vline_loop;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void clrtop(void) {
 | |
| 
 | |
| 	// f836
 | |
| 	y=0x27;
 | |
| 	ram[V2]=y;
 | |
| 	y=0x27;
 | |
| clrsc3:
 | |
| 	a=0x0;
 | |
| 	ram[COLOR]=a;
 | |
| 	vline();
 | |
| 	y--;
 | |
| 	if (y<=0x80) goto clrsc3;
 | |
| }
 | |
| 
 | |
| static void setgr(void) {
 | |
| 
 | |
| 	// FB40
 | |
| 	// SETGR
 | |
| 	soft_switch(TXTCLR);	// LDA	TXTCLR
 | |
| 	soft_switch(MIXSET);	// LDA	MIXSET
 | |
| 
 | |
| 	clrtop();
 | |
| 
 | |
| 	a=0x14;
 | |
| 	setwnd();
 | |
| 
 | |
| }
 | |
| 
 | |
| int gr(void) {
 | |
| 
 | |
| 	// F390
 | |
| 	soft_switch(LORES);	// LDA SW.LORES
 | |
| 	soft_switch(MIXSET);	// LDA SW.MIXSET
 | |
| 	//JMP MON.SETGR
 | |
| 
 | |
| 	setgr();
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int bload(char *filename, int address) {
 | |
| 
 | |
| 	FILE *fff;
 | |
| 	int count=0,ch=0;
 | |
| 
 | |
| 	fff=fopen(filename,"r");
 | |
| 	if (fff==NULL) {
 | |
| 		fprintf(stderr,"Could not open %s\n",filename);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	while(1) {
 | |
| 
 | |
| 		if ((address+count)>RAMSIZE) {
 | |
| 			fprintf(stderr,"ERROR ram too high\n");
 | |
| 			return -1;
 | |
| 		}
 | |
| 
 | |
| 
 | |
| 		ch=fgetc(fff);
 | |
| 		if (ch<0) break;
 | |
| 
 | |
| 		ram[address+count]=ch;
 | |
| 		count++;
 | |
| 	}
 | |
| 	fclose(fff);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| static int cleolz(void) {
 | |
| 	// FC9E
 | |
| 
 | |
| 	a=0xa0;
 | |
| clreol2:
 | |
| 	ram[y_indirect(BASL,y)]=a;
 | |
| 	y++;
 | |
| 
 | |
| 	if (y<ram[WNDWDTH]) goto clreol2;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int cleop1(void) {
 | |
| 
 | |
| 	unsigned char s;
 | |
| 
 | |
| cleop1_begin:
 | |
| 	s=a;
 | |
| 	vtabz();
 | |
| 	cleolz();
 | |
| 	y=0x00;
 | |
| 	a=s;
 | |
| 	a++;
 | |
| 	if (a<=ram[WNDBTM]) goto cleop1_begin;
 | |
| 	rom_vtab();
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int home(void) {
 | |
| 
 | |
| 	/* FC58 */
 | |
| 	a=ram[WNDTOP];
 | |
| 	ram[CV]=a;
 | |
| 	y=0x00;
 | |
| 	ram[CH]=y;
 | |
| 	cleop1();
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int grsim_unrle_original(unsigned char *rle_data, int address) {
 | |
| 
 | |
| 	unsigned char s;
 | |
| 
 | |
| 	ram[GBASL]=0;			/* input address */
 | |
| 	ram[GBASH]=0;			/* we fake this in this environment */
 | |
| 
 | |
| 	x=0;				/* Set X and Y registers to 0 */
 | |
| 	y=0;
 | |
| 
 | |
| 	ram[BASL]=address&0xff;		/* output address? */
 | |
| 	ram[BASH]=(address>>8)&0xff;
 | |
| 
 | |
| 	ram[CV]=0;
 | |
| 
 | |
| 	/* Read xsize, put in CH */
 | |
| 	ram[CH]=rle_data[y_indirect(GBASL,y)];
 | |
| 	y++;
 | |
| 
 | |
| 	/* Skip ysize, we won't need it */
 | |
| 	y++;
 | |
| 
 | |
| 	while(1) {
 | |
| 		/* Get run length into a */
 | |
| 		a=rle_data[y_indirect(GBASL,y)];
 | |
| 
 | |
| 		/* 0xff is a special value meaning end */
 | |
| 		if (a==0xff) break;
 | |
| 
 | |
| 		/* Store run length into TEMP */
 | |
| 		ram[TEMP]=a;
 | |
| 
 | |
| 		/* 16-bit increment of GBASL:GBASH */
 | |
| 		y++;
 | |
| 		if (y==0) ram[GBASH]++;
 | |
| 
 | |
| 		/* Get the color into A */
 | |
| 
 | |
| 		a=rle_data[y_indirect(GBASL,y)];
 | |
| 
 | |
| 		/* 16-bit increment of GBASL:GBASH */
 | |
| 		y++;
 | |
| 		if (y==0) ram[GBASH]++;
 | |
| 
 | |
| 		/* Push y on stack */
 | |
| 		s=y;
 | |
| 		y=0;
 | |
| 
 | |
| 		while(1) {
 | |
| 			/* store out color */
 | |
| 			ram[y_indirect(BASL,y)]=a;
 | |
| 
 | |
| 			/* 16-bit increment of output pointer */
 | |
| 			ram[BASL]++;
 | |
| 			if (ram[BASL]==0) ram[BASH]++;
 | |
| 
 | |
| 			/* increment size */
 | |
| 			x++;
 | |
| 
 | |
| 			/* if size longer than width, adjust */
 | |
| 			if (x>=ram[CH]) {
 | |
| 				if (ram[BASL]>0xa7) ram[BASH]++;
 | |
| 				ram[BASL]+=0x58;
 | |
| 				ram[CV]+=2;
 | |
| 				if (ram[CV]>14) {
 | |
| 					ram[CV]=0;
 | |
| 					if (ram[BASL]<0xd8) {
 | |
| 						ram[BASL]=ram[BASL]-0xd8;
 | |
| 						ram[BASH]=ram[BASH]-0x4;
 | |
| 					}
 | |
| 					else {
 | |
| 						ram[BASL]=ram[BASL]-0xd8;
 | |
| 						ram[BASH]=ram[BASH]-0x3;
 | |
| 					}
 | |
| 				}
 | |
| 				x=0;
 | |
| 			}
 | |
| 
 | |
| 			/* repeat until use up all of run length */
 | |
| 			ram[TEMP]--;
 | |
| 			if (ram[TEMP]==0) break;
 | |
| 		}
 | |
| 		/* restore y from stack */
 | |
| 		y=s;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int grsim_unrle(unsigned char *rle_data, int address) {
 | |
| 
 | |
| 	unsigned char s;
 | |
| 
 | |
| 	ram[GBASL]=0;			/* input address */
 | |
| 	ram[GBASH]=0;			/* we fake this in this environment */
 | |
| 
 | |
| 	x=0;				/* Set X and Y registers to 0 */
 | |
| 	y=0;
 | |
| 
 | |
| 	ram[BASL]=address&0xff;		/* output address? */
 | |
| 	ram[BASH]=(address>>8)&0xff;
 | |
| 
 | |
| 	ram[CV]=0;
 | |
| 
 | |
| 	/* Read xsize, put in CH */
 | |
| 	ram[CH]=rle_data[y_indirect(GBASL,y)];
 | |
| 	y++;
 | |
| 
 | |
| 	/* Skip ysize, we won't need it */
 | |
| //	y++;
 | |
| 
 | |
| 	while(1) {
 | |
| 
 | |
| 		/* Get byte into A */
 | |
| 		a=rle_data[y_indirect(GBASL,y)];
 | |
| 
 | |
| 		/* 0xa1 is a special value meaning end */
 | |
| 		if (a==0xa1) break;
 | |
| 
 | |
| 		/* Store run length into TEMP */
 | |
| 		if ((a&0xf0)==0xa0) {
 | |
| 			if ((a&0xf)==0) {
 | |
| 				/* 16-bit increment of GBASL:GBASH */
 | |
| 				y++;
 | |
| 				if (y==0) ram[GBASH]++;
 | |
| 
 | |
| 				a=rle_data[y_indirect(GBASL,y)];
 | |
| 				ram[TEMP]=a;
 | |
| 
 | |
| 			}
 | |
| 			else {
 | |
| 				ram[TEMP]=a&0xf;
 | |
| 			}
 | |
| 
 | |
| 			/* 16-bit increment of GBASL:GBASH */
 | |
| 			y++;
 | |
| 			if (y==0) ram[GBASH]++;
 | |
| 
 | |
| 			/* Get the color into A */
 | |
| 			a=rle_data[y_indirect(GBASL,y)];
 | |
| 
 | |
| 		}
 | |
| 		else {
 | |
| 			ram[TEMP]=1;
 | |
| 		}
 | |
| 
 | |
| 		/* 16-bit increment of GBASL:GBASH */
 | |
| 		y++;
 | |
| 		if (y==0) ram[GBASH]++;
 | |
| 
 | |
| 		/* Push y on stack */
 | |
| 		s=y;
 | |
| 		y=0;
 | |
| 
 | |
| #if 0
 | |
| 	{
 | |
| 		printf("Run=%d Color=%x\n",ram[TEMP],a);
 | |
| 	}
 | |
| #endif
 | |
| 		while(1) {
 | |
| 			/* store out color */
 | |
| 			ram[y_indirect(BASL,y)]=a;
 | |
| 
 | |
| 			/* 16-bit increment of output pointer */
 | |
| 			ram[BASL]++;
 | |
| 			if (ram[BASL]==0) ram[BASH]++;
 | |
| 
 | |
| 			/* increment size */
 | |
| 			x++;
 | |
| 
 | |
| 			/* if size longer than width, adjust */
 | |
| 			if (x>=ram[CH]) {
 | |
| 				if (ram[BASL]>0xa7) ram[BASH]++;
 | |
| 				ram[BASL]+=0x58;
 | |
| 				ram[CV]+=2;
 | |
| 				if (ram[CV]>14) {
 | |
| 					ram[CV]=0;
 | |
| 					if (ram[BASL]<0xd8) {
 | |
| 						ram[BASL]=ram[BASL]-0xd8;
 | |
| 						ram[BASH]=ram[BASH]-0x4;
 | |
| 					}
 | |
| 					else {
 | |
| 						ram[BASL]=ram[BASL]-0xd8;
 | |
| 						ram[BASH]=ram[BASH]-0x3;
 | |
| 					}
 | |
| 				}
 | |
| 				x=0;
 | |
| 			}
 | |
| 
 | |
| 			/* repeat until use up all of run length */
 | |
| 			ram[TEMP]--;
 | |
| 			if (ram[TEMP]==0) break;
 | |
| 		}
 | |
| 		/* restore y from stack */
 | |
| 		y=s;
 | |
| 
 | |
| #if 0
 | |
| 	{
 | |
| 		grsim_update();
 | |
| 		int ch;
 | |
| 		ch=repeat_until_keypressed();
 | |
| 		grsim_update();
 | |
| 		if (ch=='q') break;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int basic_vlin(int y1, int y2, int at) {
 | |
| 
 | |
| 	// f244
 | |
| 
 | |
| 	// LINCOOR
 | |
| 	// GET "A,B AT C"
 | |
| 	// PUT SMALLER OF (A,B) IN FIRST,
 | |
|         // AND LARGER  OF (A,B) IN H2 AND V2.
 | |
|         // RETURN WITH (X) = C-VALUE.
 | |
| 
 | |
| 	if (y1>y2) { ram[H2]=y1; ram[V2]=y1; ram[FIRST]=y2; }
 | |
| 	else       { ram[H2]=y2; ram[V2]=y2; ram[FIRST]=y1; }
 | |
| 	x=at;
 | |
| 
 | |
| 	if (x>40) {
 | |
| 		fprintf(stderr,"Error!  AT too large %d!\n",x);
 | |
| 	}
 | |
| 
 | |
| //VLIN  JSR LINCOOR
 | |
| //F244- 8A       2050        TXA          X-COORD IN Y-REG
 | |
| //F245- A8       2060        TAY
 | |
| //F246- C0 28    2070        CPY #40      X-COORD MUST BE < 40
 | |
| //F248- B0 BC    2080        BCS GOERR    TOO LARGE
 | |
| //F24A- A5 F0    2090        LDA FIRST    TOP END OF LINE IN A-REG
 | |
| //F24C- 4C 28 F8 2100        JMP MON.VLINE     LET MONITOR DRAW LINE
 | |
| 
 | |
| 	y=x;
 | |
| 	if (y>=40) {
 | |
| 		fprintf(stderr,"X value to big in vline %d\n",y);
 | |
| 		return -1;
 | |
| 	}
 | |
| 	a=ram[FIRST];
 | |
| 
 | |
| 	vline();
 | |
| 
 | |
| //	for(i=y1;i<y2;i++) basic_plot(at,i);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| int grsim_put_sprite_page(int page, unsigned char *sprite_data, int xpos, int ypos) {
 | |
| 
 | |
| 	unsigned char i;
 | |
| 	unsigned char *ptr;
 | |
| 	short address;
 | |
| 	int cycles=0;
 | |
| 
 | |
| 	ptr=sprite_data;
 | |
| 	x=*ptr;
 | |
| 	ptr++;
 | |
| 	ram[CV]=*ptr;
 | |
| 	ptr++;
 | |
| 
 | |
| 	ypos=ypos&0xfe;
 | |
| 
 | |
| 							cycles+=28;
 | |
| 
 | |
| 	while(1) {
 | |
| 		address=gr_addr_lookup[ypos/2];
 | |
| 		address+=(page)<<8;
 | |
| 		address+=xpos;
 | |
| 							cycles+=36;
 | |
| 		for(i=0;i<x;i++) {
 | |
| 			a=*ptr;
 | |
| 							cycles+=17;
 | |
| 			// all transparent, skip
 | |
| 			if (a==0xaa) {
 | |
| 			}
 | |
| 			// bottom transparent
 | |
| 			else if ((a&0xf0)==0xa0) {
 | |
| 							cycles+=8;
 | |
| 				ram[address]&=0xf0;
 | |
| 				ram[address]|=(a&0xf);
 | |
| 							cycles+=19;
 | |
| 			}
 | |
| 			// top transparent
 | |
| 			else if ((a&0x0f)==0xa) {
 | |
| 							cycles+=8;
 | |
| 				ram[address]&=0x0f;
 | |
| 				ram[address]|=(a&0xf0);
 | |
| 							cycles+=19;
 | |
| 			}
 | |
| 			else {
 | |
| 							cycles+=8;
 | |
| 				ram[address]=a;
 | |
| 							cycles+=19;
 | |
| 			}
 | |
| 			ptr++;
 | |
| 			address++;
 | |
| 							cycles+=13;
 | |
| 		}
 | |
| 		ypos+=2;
 | |
| 		ram[CV]--;
 | |
| 		if (ram[CV]==0) break;
 | |
| 							cycles+=18;
 | |
| 	}
 | |
| 							cycles+=6;
 | |
| 	return cycles;
 | |
| }
 | |
| 
 | |
| int grsim_put_sprite(unsigned char *sprite_data, int xpos, int ypos) {
 | |
| 
 | |
| 	int cycles;
 | |
| 
 | |
| 	cycles=grsim_put_sprite_page(ram[DRAW_PAGE],sprite_data,xpos,ypos);
 | |
| 
 | |
| 	return cycles;
 | |
| }
 | |
| 
 | |
| 
 | |
| int gr_copy(short source, short dest) {
 | |
| 
 | |
| 	short dest_addr,source_addr;
 | |
| 	int i,j,l;
 | |
| 
 | |
| 	for(i=0;i<8;i++) {
 | |
| 		source_addr=gr_addr_lookup[i]+(source-0x400);
 | |
| 		dest_addr=gr_addr_lookup[i]+(dest-0x400);
 | |
| 
 | |
| 		if (i<4) l=120;
 | |
| 		else l=80;
 | |
| 
 | |
| 		for(j=0;j<l;j++) {
 | |
| 			ram[dest_addr+j]=ram[source_addr+j];
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int gr_copy_to_current(short source) {
 | |
| 
 | |
| 	short dest_addr,source_addr;
 | |
| 	int i,j,l;
 | |
| 
 | |
| 	for(i=0;i<8;i++) {
 | |
| 		source_addr=gr_addr_lookup[i]+(source-0x400);
 | |
| 		dest_addr=gr_addr_lookup[i]+(ram[DRAW_PAGE]<<8);
 | |
| 
 | |
| //		if (i<4) l=120;	// only copy 40 lines
 | |
| //		else l=80;
 | |
| 
 | |
| 		l=120;	// copy 48 lines
 | |
| 
 | |
| 		for(j=0;j<l;j++) {
 | |
| 			ram[dest_addr+j]=ram[source_addr+j];
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int gr_copy48(short source, short dest) {
 | |
| 
 | |
| 	short dest_addr,source_addr;
 | |
| 	int i,j;
 | |
| 
 | |
| 	for(i=0;i<8;i++) {
 | |
| 		source_addr=gr_addr_lookup[i]+0x400;
 | |
| 		dest_addr=gr_addr_lookup[i];
 | |
| 
 | |
| 		for(j=0;j<120;j++) {
 | |
| 			ram[dest_addr+j]=ram[source_addr+j];
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| int text(void) {
 | |
| 	// FB36
 | |
| 
 | |
| 	soft_switch(LOWSCR);	// LDA LOWSCR ($c054)
 | |
| 	soft_switch(TXTSET);	// LDA TXTSET ($c051);
 | |
| 	a=0;
 | |
| 
 | |
| 	setwnd();
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void scroll(void) {
 | |
| 	unsigned char s;
 | |
| 
 | |
| 	// fc70
 | |
| 
 | |
| 	a=ram[WNDTOP];
 | |
| 	s=a;
 | |
| 	vtabz();
 | |
| 
 | |
| 	// SCRL1
 | |
| scrl1:
 | |
| 	a=ram[BASL];
 | |
| 	ram[BAS2L]=a;
 | |
| 	a=ram[BASH];
 | |
| 	ram[BAS2H]=a;
 | |
| 	y=ram[WNDWDTH];
 | |
| 	y--;
 | |
| 	a=s;
 | |
| 	a+=1;
 | |
| 	if (a>=ram[WNDBTM]) {
 | |
| 		// SCRL3
 | |
| 		y=0;
 | |
| 		cleolz();
 | |
| 		rom_vtab();
 | |
| 		return;
 | |
| 	}
 | |
| 	s=a;
 | |
| 	vtabz();
 | |
| 	// SCRL2
 | |
| scrl2:
 | |
| 	a=ram[y_indirect(BASL,y)];
 | |
| 	ram[y_indirect(BAS2L,y)]=a;
 | |
| 	y--;
 | |
| 	if (y<0x80) goto scrl2;
 | |
| 	goto scrl1;
 | |
| }
 | |
| 
 | |
| static void lf(void) {
 | |
| 	ram[CV]=ram[CV]+1;
 | |
| 	a=ram[CV];
 | |
| 	if (a<ram[WNDBTM]) {
 | |
| 		vtabz();
 | |
| 		return;
 | |
| 	}
 | |
| 	ram[CV]=ram[CV]-1;
 | |
| 	scroll();
 | |
| }
 | |
| 
 | |
| static void cr(void) {
 | |
| 	a=0x00;
 | |
| 	ram[CH]=a;
 | |
| 	lf();
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| static void bell1(void) {
 | |
| }
 | |
| 
 | |
| static void up(void) {
 | |
| 
 | |
| 	a=ram[WNDTOP];
 | |
| 	if (a>ram[CV]) return;
 | |
| 
 | |
| 	ram[CV]=ram[CV]-1;
 | |
| 	rom_vtab();
 | |
| }
 | |
| 
 | |
| static void bs(void) {
 | |
| 
 | |
| 	ram[CH]=ram[CH]-1;
 | |
| 
 | |
| 	/* still positive */
 | |
| 	if (ram[CH]<0x80) return;
 | |
| 
 | |
| 	a=ram[WNDWDTH];
 | |
| 	ram[CH]=a;
 | |
| 	ram[CH]=ram[CH]-1;
 | |
| 
 | |
| 	up();
 | |
| }
 | |
| 
 | |
| static void storadv(void) {
 | |
| 
 | |
| 	// fbf0
 | |
| 
 | |
| 	y=ram[CH];
 | |
| 	ram[y_indirect(BASL,y)]=a;
 | |
| 
 | |
| 	// advance
 | |
| 
 | |
| 	ram[CH]=ram[CH]+1;
 | |
| 	a=ram[CH];
 | |
| 	if (a>=ram[WNDWDTH]) {
 | |
| 		cr();
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| static void vidout(void) {
 | |
| 	// fbfd
 | |
| 
 | |
| 	if (a>=0xa0) {
 | |
| 		storadv();
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* Control Characters */
 | |
| 	y=a;
 | |
| 	// if bit 7 is set then we set negative flag
 | |
| 	// BPL storadv
 | |
| 	if (a<0x80) {
 | |
| 		storadv();
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* carriage return */
 | |
| 	if (a==0x8d) {
 | |
| 		cr();
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* linefeed */
 | |
| 	if (a==0x8a) {
 | |
| 		lf();
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* backspace */
 | |
| 	if (a==0x88) {
 | |
| 		bs();
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* any other control code, beep */
 | |
| 	bell1();
 | |
| 	return;
 | |
| 
 | |
| }
 | |
| 
 | |
| static void vidwait(void) {
 | |
| 	// check if control-S being pressed
 | |
| 
 | |
| 	vidout();
 | |
| }
 | |
| 
 | |
| static void cout1(void) {
 | |
| 
 | |
| 	unsigned char s;
 | |
| 
 | |
| 	if (a<0xa0) {
 | |
| 	}
 | |
| 	else {
 | |
| 		a=a&ram[INVFLG];
 | |
| 	}
 | |
| 	// coutz
 | |
| 	ram[YSAV1]=y;
 | |
| 	s=a;
 | |
| 
 | |
| 	vidwait();
 | |
| 
 | |
| 	a=s;
 | |
| 	y=ram[YSAV1];
 | |
| 
 | |
| }
 | |
| 
 | |
| static void cout(void) {
 | |
| 	// FDED
 | |
| 	//	jmp (cswl)	custom handler
 | |
| 	cout1();
 | |
| }
 | |
| 
 | |
| static void wait(void) {
 | |
| }
 | |
| 
 | |
| static void outdo(void) {
 | |
| 
 | |
| 	unsigned char s;
 | |
| 
 | |
| 	/* Print char in the accumulator */
 | |
| 	a=a|0x80;		/* raw ascii has high bit on Apple II */
 | |
| 	if (a<0xa0) {
 | |
| 		/* skip if control char? */
 | |
| 	}
 | |
| 	else {
 | |
| 		a=a|ram[FLASH];
 | |
| 	}
 | |
| 	cout();
 | |
| 	a=a&0x7f;	// ?
 | |
| 	s=a;		// pha
 | |
| 	a=ram[SPEEDZ];
 | |
| 	wait(); 	// this is BASIC, slow down if speed set
 | |
| 	a=s;
 | |
| }
 | |
| 
 | |
| static void crdo(void) {
 | |
| 	// DAFB
 | |
| 	a=13;	// carriage return
 | |
| 	outdo();
 | |
| 	a=a^0xff;		/* negate for some reason? */
 | |
| }
 | |
| 
 | |
| void basic_htab(int xpos) {
 | |
| 
 | |
| 	unsigned char s;
 | |
| 
 | |
| 	// F7E7
 | |
| 
 | |
| 
 | |
| 	x=xpos;	// JSR GETBYT
 | |
| 	x--;	// DEX
 | |
| 	a=x;	// TXA
 | |
| 	while(a>=40) {
 | |
| 		s=a;	// PHA
 | |
| 		crdo();
 | |
| 		a=s;	// PLA
 | |
| 		a-=40;
 | |
| 	}
 | |
| 	ram[CH]=a;	// STA MON.CH
 | |
| 
 | |
| 	// KRW for the win!
 | |
| 
 | |
| }
 | |
| 
 | |
| static void tabv(void) {
 | |
| 
 | |
| 	// TABV
 | |
| 	// fb5b
 | |
| 	ram[CV]=a;
 | |
| 	rom_vtab();
 | |
| }
 | |
| 
 | |
| void basic_vtab(int ypos) {
 | |
| 	// f256
 | |
| 	x=ypos;
 | |
| 	x--;		/* base on zero */
 | |
| 	a=x;
 | |
| 
 | |
| 	if (a>23) {
 | |
| 		fprintf(stderr,"Error, vtab %d too big\n",ypos);
 | |
| 		return;
 | |
| 	}
 | |
| 	tabv();
 | |
| }
 | |
| 
 | |
| void basic_print(char *string) {
 | |
| 
 | |
| 	int i;
 | |
| 
 | |
| 	for(i=0;i<strlen(string);i++) {
 | |
| 		a=string[i];
 | |
| 		outdo();
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| void basic_inverse(void) {
 | |
| 	// F277
 | |
| 	a=0x3f;
 | |
| 	x=0;
 | |
| 	ram[INVFLG]=a;
 | |
| 	ram[FLASH]=x;
 | |
| 
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| void basic_normal(void) {
 | |
| 	// F273
 | |
| 	a=0xff;
 | |
| 	x=0;
 | |
| 	ram[INVFLG]=a;
 | |
| 	ram[FLASH]=x;
 | |
| 
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| static unsigned short hlin_addr;
 | |
| static unsigned short hlin_hi;
 | |
| 
 | |
| 
 | |
| int hlin_continue(int width) {
 | |
| 
 | |
| 	int i;
 | |
| 
 | |
| 	for(i=0;i<width;i++) {
 | |
| 		if (hlin_hi) {
 | |
| 			ram[hlin_addr]=ram[hlin_addr]&0x0f;
 | |
| 			ram[hlin_addr]|=ram[COLOR]&0xf0;
 | |
| 		}
 | |
| 		else {
 | |
| 			ram[hlin_addr]=ram[hlin_addr]&0xf0;
 | |
| 			ram[hlin_addr]|=ram[COLOR]&0x0f;
 | |
| 		}
 | |
| 		hlin_addr++;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| int plot(unsigned char xcoord, unsigned char ycoord) {
 | |
| 
 | |
| 	unsigned char c;
 | |
| 
 | |
| 	hlin_addr=gr_addr_lookup[ycoord/2];
 | |
| 	hlin_addr+=(ram[DRAW_PAGE])<<8;
 | |
| 	hlin_addr+=xcoord;
 | |
| 
 | |
| 	hlin_hi=ycoord&1;
 | |
| 
 | |
| 	if (hlin_hi) {
 | |
| 		/* If odd, mask is 0xf0 */
 | |
| 		ram[MASK]=0xf0;
 | |
| 	}
 | |
| 	else {
 | |
| 		/* If even, mask is 0x0f */
 | |
| 		ram[MASK]=0x0f;
 | |
| 	}
 | |
| 
 | |
| 	c=ram[COLOR]&ram[MASK];
 | |
| 	ram[hlin_addr]&=~ram[MASK];
 | |
| 	ram[hlin_addr]|=c;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| int hlin(int page, int x1, int x2, int at) {
 | |
| 
 | |
| 	hlin_addr=gr_addr_lookup[at/2];
 | |
| 	hlin_hi=at&1;
 | |
| 
 | |
| 	hlin_addr+=(page)<<8;
 | |
| 
 | |
| 	hlin_addr+=x1;
 | |
| 	hlin_continue(x2-x1);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static unsigned short vlin_hi;
 | |
| 
 | |
| /* TODO: optimize */
 | |
| /* Could make twice as fast if draw neighboring two in one write */
 | |
| /* instead of two */
 | |
| 
 | |
| int vlin(int y1, int y2, int at) {
 | |
| 
 | |
| 	x=y1;
 | |
| 	ram[V2]=y2;
 | |
| 	y=at;
 | |
| 
 | |
| vlin_loop:
 | |
| //	for(a=y1;a<y2;a++) {
 | |
| 
 | |
| 		ram[TEMPY]=y;
 | |
| 		a=x;
 | |
| 		y=a/2;
 | |
| 
 | |
| 		ram[OUTL]=gr_addr_lookup[y]&0xff;
 | |
| 		ram[OUTH]=(gr_addr_lookup[y]>>8)&0xff;
 | |
| 
 | |
| 		ram[OUTH]+=ram[DRAW_PAGE];
 | |
| 
 | |
| 		vlin_hi=x&1;
 | |
| 
 | |
| 		y=ram[TEMPY];	// y=at;
 | |
| 
 | |
| 		if (vlin_hi) {
 | |
| 			ram[y_indirect(OUTL,y)]=ram[y_indirect(OUTL,y)]&0x0f;
 | |
| 			ram[y_indirect(OUTL,y)]|=ram[COLOR]&0xf0;
 | |
| 		}
 | |
| 		else {
 | |
| 			ram[y_indirect(OUTL,y)]=ram[y_indirect(OUTL,y)]&0xf0;
 | |
| 			ram[y_indirect(OUTL,y)]|=ram[COLOR]&0x0f;
 | |
| 		}
 | |
| 	x++;
 | |
| 	if (x<ram[V2]) goto vlin_loop;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int hlin_double_continue(int width) {
 | |
| 
 | |
| 	x=width;
 | |
| 
 | |
| hlin_loop:
 | |
| 	y=0;
 | |
| 	ram[y_indirect(GBASL,y)]=ram[COLOR];
 | |
| 	ram[GBASL]++;
 | |
| 	x--;
 | |
| 	if (x!=0) goto hlin_loop;
 | |
| 
 | |
| //	ram[GBASL]+=width;
 | |
| 
 | |
| //	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int hlin_setup(int page, int x1, int x2, int at) {
 | |
| 
 | |
| 	// page, y, V2, A
 | |
| 	a=at;
 | |
| 	y=at/2;
 | |
| 
 | |
| 	ram[GBASL]=(gr_addr_lookup[y])&0xff;
 | |
| 	ram[GBASH]=(gr_addr_lookup[y]>>8);
 | |
| 
 | |
| 	ram[GBASH]+=(page);
 | |
| 
 | |
| 	ram[GBASL]+=x1;
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| }
 | |
| 
 | |
| int hlin_double(int page, int x1, int x2, int at) {
 | |
| 
 | |
| 	hlin_setup(page,x1,x2,at);
 | |
| 
 | |
| 	hlin_double_continue(x2-x1+1);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| #if 0
 | |
| int collision(int xx, int yy, int ground_color) {
 | |
| 
 | |
| 	int page=0;
 | |
| 	int beach_color;
 | |
| 	int collide=1;
 | |
| 
 | |
| 	hlin_addr=gr_addr_lookup[yy/2];
 | |
| 
 | |
| 	hlin_addr+=(page)<<8;
 | |
| 
 | |
| 	hlin_addr+=xx;
 | |
| 
 | |
| 	beach_color=COLOR_YELLOW|(COLOR_YELLOW<<4);
 | |
| 
 | |
| 	if ((ram[hlin_addr]==ground_color) &&
 | |
| 		(ram[hlin_addr+1]==ground_color) &&
 | |
| 		(ram[hlin_addr+2]==ground_color)) {
 | |
| 
 | |
| 		printf("NOCOLLIDE %x!\n",ground_color);
 | |
| 		collide=0;
 | |
| 	}
 | |
| 
 | |
| 	if ((ram[hlin_addr]==beach_color) &&
 | |
| 		(ram[hlin_addr+1]==beach_color) &&
 | |
| 		(ram[hlin_addr+2]==beach_color)) {
 | |
| 
 | |
| 		printf("NOCOLLIDE %x!\n",beach_color);
 | |
| 		collide=0;
 | |
| 	}
 | |
| 
 | |
| 	printf("COLLIDE %x %x %x not %x %x\n",
 | |
| 		ram[hlin_addr],ram[hlin_addr+1],ram[hlin_addr+2],
 | |
| 		ground_color,beach_color);
 | |
| 
 | |
| 	return collide;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if 0
 | |
| 
 | |
| void clear_top_a(void) {
 | |
| 
 | |
| 	int i;
 | |
| 
 | |
| 	ram[COLOR]=a;
 | |
| 	for(i=0;i<40;i+=2) {
 | |
| 		hlin_double(ram[DRAW_PAGE],0,40,i);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void clear_top(int page) {
 | |
| 	int i;
 | |
| 
 | |
| 	ram[COLOR]=0x0;
 | |
| 	for(i=0;i<40;i+=2) {
 | |
| 		hlin_double(page,0,40,i);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void clear_bottom(int page) {
 | |
| 	int i;
 | |
| 
 | |
| 	/* NORMAL space */
 | |
| 	ram[COLOR]=0xa0;
 | |
| 	for(i=40;i<48;i+=2) {
 | |
| 		hlin_double(page,0,40,i);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| void vtab(int ypos) {
 | |
| 	ram[CV]=ypos-1;
 | |
| }
 | |
| 
 | |
| void htab(int xpos) {
 | |
| 	ram[CH]=xpos-1;
 | |
| }
 | |
| 
 | |
| void move_cursor(void) {
 | |
| 
 | |
| 	int address;
 | |
| 
 | |
| 	address=gr_addr_lookup[ram[CV]];
 | |
| 	address+=ram[CH];
 | |
| 
 | |
| 	address+=(ram[DRAW_PAGE]<<8);
 | |
| 
 | |
| 	ram[BASL]=address&0xff;
 | |
| 	ram[BASH]=address>>8;
 | |
| 
 | |
| }
 | |
| 
 | |
| void print_both_pages(char *string) {
 | |
| 	unsigned char temp;
 | |
| 
 | |
| 	temp=ram[DRAW_PAGE];
 | |
| 
 | |
| 	ram[DRAW_PAGE]=0;
 | |
| 	move_and_print(string);
 | |
| 
 | |
| 	ram[DRAW_PAGE]=4;
 | |
| 	move_and_print(string);
 | |
| 
 | |
| 	ram[DRAW_PAGE]=temp;
 | |
| 
 | |
| }
 | |
| 
 | |
| void move_and_print(char *string) {
 | |
| 
 | |
| 	int address;
 | |
| 
 | |
| 	address=gr_addr_lookup[ram[CV]];
 | |
| 	address+=ram[CH];
 | |
| 
 | |
| 	address+=(ram[DRAW_PAGE]<<8);
 | |
| 
 | |
| 	ram[BASL]=address&0xff;
 | |
| 	ram[BASH]=address>>8;
 | |
| 
 | |
| 	print(string);
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| void print(char *string) {
 | |
| 
 | |
| 	for(y=0;y<strlen(string);y++) {
 | |
| 		a=string[y];
 | |
| 		a=a|0x80;
 | |
| 		ram[y_indirect(BASL,y)]=a;
 | |
| 	}
 | |
| 	ram[BASL]+=strlen(string);
 | |
| }
 | |
| 
 | |
| void print_inverse(char *string) {
 | |
| 
 | |
| 	for(y=0;y<strlen(string);y++) {
 | |
| 		a=string[y];
 | |
| 		if ((a>='a') && (a<='z')) a&=~0x20;	// convert to uppercase
 | |
| 		a=(a&0x3f);
 | |
| 
 | |
| 		ram[y_indirect(BASL,y)]=a;
 | |
| 	}
 | |
| 	ram[BASL]+=strlen(string);
 | |
| }
 | |
| 
 | |
| void print_flash(char *string) {
 | |
| 
 | |
| 	for(y=0;y<strlen(string);y++) {
 | |
| 		a=string[y];
 | |
| 		a=(a&0x3f)|0x40;
 | |
| 		ram[y_indirect(BASL,y)]=a;
 | |
| 	}
 | |
| 	ram[BASL]+=strlen(string);
 | |
| }
 |