⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 console_demo.c

📁 ARMULATOR的原代码AR MULATOR的原代码ARMULATOR的原代码
💻 C
字号:
/*

Graphics demo for Console model

NOTE: THIS DEMO ONLY WORKS FOR 8 OR 2 BITS/PIXEL!

*/

#include "..\console.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"

#define MIN(x,y) x < y ? x : y;
#define MAX(x,y) x < y ? y : x;

/*
typedef struct tagBITMAPFILEHEADER {
        WORD    bfType;
        DWORD   bfSize;
        WORD    bfReserved1;
        WORD    bfReserved2;
        DWORD   bfOffBits;
} BITMAPFILEHEADER
*/

typedef __packed struct tagBITMAPFILEHEADER {
        unsigned short    bfType;
        unsigned int   bfSize;
        unsigned short    bfReserved1;
        unsigned short    bfReserved2;
        unsigned int   bfOffBits;
} BITMAPFILEHEADER;

extern BITMAPFILEHEADER armlogo;
extern BITMAPFILEHEADER chars;
extern BITMAPFILEHEADER backdrop;

/*
typedef struct tagBITMAPINFOHEADER{
        DWORD      biSize;
        LONG       biWidth;
        LONG       biHeight;
        WORD       biPlanes;
        WORD       biBitCount;
        DWORD      biCompression;
        DWORD      biSizeImage;
        LONG       biXPelsPerMeter;
        LONG       biYPelsPerMeter;
        DWORD      biClrUsed;
        DWORD      biClrImportant;
} BITMAPINFOHEADER */

typedef __packed struct tagBITMAPINFOHEADER{
        unsigned int      biSize;
        int       biWidth;
        int       biHeight;
        unsigned short       biPlanes;
        unsigned short       biBitCount;
        unsigned int      biCompression;
        unsigned int      biSizeImage;
        int       biXPelsPerMeter;
        int       biYPelsPerMeter;
        unsigned int      biClrUsed;
        unsigned int      biClrImportant;
} BITMAPINFOHEADER;

/* typedef struct tagRECT
{
    LONG    left;
    LONG    top;
    LONG    right;
    LONG    bottom;
} RECT
*/

typedef struct tagRECT
{
    int    left;
    int    top;
    int    right;
    int    bottom;
} RECT;

// Define this to use inline assembler drawing routines for speed
#define FAST_DRAW

unsigned Install_Handler( unsigned routine, unsigned *vector );
__inline void enable_IRQ(void);
void __irq myIRQhandler(void);

  /* Write a character     */ 
//__swi(SemiSWI) void _WriteC(unsigned op, char *c);
//#define WriteC(c) _WriteC (0x3,c)
struct __FILE { int handle; /* Add whatever you need here */};
//FILE __stdout;

volatile int keyflag = 0;	// used to indicate when a key has been pressed
int getc_echo = 0;			// used to specify whether getc call will echo or not
static RECT curr_pos = { 0, 0, 0, 0 }; // used by fputc for positioning

/* Helper function prototypes */

unsigned random( unsigned min, unsigned max );

/* info funcs ***************************/
__inline unsigned getPixelsX( void );
__inline unsigned getPixelsY( void );

/* setup funcs **************************/
void initLCD( void );

/* attribute funcs **********************/

/* 2 bpp */
/* #define BYTES_PER_LINE (unsigned)120 */

/* 8 bpp */
//#define BYTES_PER_LINE (unsigned)480
// this needs tweaking to get on a DWORD boundrary
#define BYTES_PER_LINE (getPixelsX()+getAlignmentTweak()) / (8 / BITS_PER_PIXEL)

/* character drawing */
#define CHAR_WIDTH 8
#define CHAR_HEIGHT 16

static char forecolor, backcolor;

__inline unsigned getAlignmentTweak( void );

__inline void setForeColor( char col );
__inline void setBackColor( char col );

/* drawing funcs ************************/
void setPixelXY( unsigned x, unsigned y );
int __inline drawSpriteXY( BITMAPFILEHEADER* pBmFile, RECT* rectSrc, RECT* rectDest );
void __inline drawCharXY( char c, RECT* rectDest );
void __inline drawStringXY( char* string, RECT* rectDest );
void __inline scrollUp( unsigned lines );

/* main drawing routines */
void demo2BPP( void );
void demo8BPP( void );

/* MAIN PROGRAM *************************/

/* TODO: add greyscale, basic sprites and scrolling */

int main()
{
	/* Set up keyboard input */
	unsigned *irqvec = (unsigned *)0x18;
	
	initLCD();

	Install_Handler( (unsigned)myIRQhandler, irqvec );
	
	/* DR added - ENABLE IRQs */
	enable_IRQ();

	switch( BITS_PER_PIXEL ) {
	case 2:
		demo2BPP();
		break;
		
	case 8:
		demo8BPP();
		break;

	default:
		// the demo does not support these color depths
		return 1;
	}

	return 0;
}

/* Simple demo in 2bpp mode */

void demo2BPP( void )
{
	/* examine corners */
	setPixelXY( 0, 0 );
	setPixelXY( getPixelsX()-1, 0 );
	setPixelXY( 0, getPixelsY()-1 );
	setPixelXY( getPixelsX()-1, getPixelsY()-1 );
	
	/* randomly turn on pixels for background */
	while(1) {
		setForeColor( random( 0, 3 ) );
		setPixelXY( random( 0, getPixelsX()-1 ), random( 0, getPixelsY()-1 ) );
	}
}

void demo8BPP( void )
{
	int i, vel;
	char c;
	RECT rectSrc, rectDest;

	/* a value of -1 indicates that source rectangle is that of whole bitmap */
	rectSrc.left = rectSrc.top = -1;
	rectSrc.right = rectSrc.bottom = -1;

	/* draw ARM logo in approx. centre of screen */

	rectDest.right = rectDest.bottom = 0;	// unused as yet
	rectDest.left = (getPixelsX() - 480) / 2;
	rectDest.top = (getPixelsY() - 240) / 2;

	// note that the backdrop has dimensions 480x240 thus this operation
	// will overwrite memory outside the display region if the size of display
	// is smaller.
	drawSpriteXY( &backdrop, &rectSrc, &rectDest );
	
	/* enable keyboard interrupts through the ODO keyb setup reg. */
	*((unsigned*)CPU_MR) |= KEYB_INTR;
	*((unsigned*)KB_CSR) |= KB_CLK_EN;

	/* Query and response */
	printf( "Hello! Enter your age: " );

	getc_echo = 1;
	scanf( "%d", &i );
	getc_echo = 0;

	printf( "\nTwice your age is: %d\n\nPress (1) for animation, (2) to type", i * 2 );
	c = getchar();

	switch( c ) {
	case '1':
	/* animation */
	i = 20;
	vel = 1;
	rectDest.top = 0;

	while(1) {
		rectDest.left = i;
		drawSpriteXY( &armlogo, &rectSrc, &rectDest );
		if( i > (getPixelsX()-64) || i < 1 ) vel = -vel;
		i += vel;
	}

		break;

	case '2':
		/* Just echo keyboard characters */
		printf( "\n\nKeystrokes will be echoed below:\n" );
		while( 1 ) putchar(getchar());
		break;

	default:
		printf( "\n\nInvalid choice - quitting" );
	}
}

__inline unsigned getPixelsX( void ) {
	return *((unsigned*)DISP_XSIZE);
}

__inline unsigned getPixelsY( void ) {
	return *((unsigned*)DISP_YSIZE);
}

__inline unsigned getAlignmentTweak( void ) {
	unsigned alignment_tweak;

	alignment_tweak = 4 - getPixelsX() % 4;
	if( alignment_tweak == 4 ) alignment_tweak = 0;

	return alignment_tweak;
}

void initLCD( void ) {
	/* fill the display with background colour */
	unsigned char* pDisp = (unsigned char*)DISPLAY_PTR;
	unsigned char* pTop;
	unsigned char temp_byte;
	int i;

	pTop = pDisp + BYTES_PER_LINE * getPixelsY();

	// set up fputc function
	curr_pos.top = getPixelsY()-CHAR_HEIGHT;

	switch( BITS_PER_PIXEL ) {
		case 2:
			setForeColor( 0 );
			setBackColor( 3 );

			// set up the byte
			temp_byte = backcolor;
			for( i = 0; i < 3; i++ ) {
				temp_byte <<= 2;
				temp_byte |= backcolor;
			}

			while( pDisp < pTop ) {
				*pDisp = temp_byte;
				pDisp++;
			}
			break;

		case 8:
			setForeColor( 0 );
			// white
			setBackColor( 215 );

			while( pDisp < pTop ) {
				*pDisp = backcolor;
				pDisp++;
			}
		break;

		default:
			return;
	}
}

__inline void setForeColor( char col ) {
	forecolor = col;
}

__inline void setBackColor( char col ) {
	backcolor = col;
}

void setPixelXY( unsigned x, unsigned y ) {
	char shift, mask, masked_old, new_byte;

	/* determine which byte to set (calculate address from x and y ) */
	char *addr;
	
	//addr = (char*)DISPLAY_PTR + y * BYTES_PER_LINE + (x >> 2);
	//addr = (char*)DISPLAY_PTR + y * BYTES_PER_LINE + x;

	addr = (char*)DISPLAY_PTR + y * BYTES_PER_LINE;

	switch( BITS_PER_PIXEL ) {
	case 2:
		addr += (x >> 2);	// divide x byte position by 4
	
		/* mask off unwanted bits in byte, shift then OR with current word. */
	
		shift = (x % 4) << 1;
	
		/* store the new pixel value */
		mask = ~(0x03 << shift);
		masked_old = (*addr) & mask;
		new_byte = (char)(masked_old | (forecolor << shift));
		*addr = new_byte;
		break;

	case 8:
		addr += x;
		*addr = forecolor;
		break;

	default:
		// not supported
		return;
	}
}

int __inline drawSpriteXY( BITMAPFILEHEADER* pBmFile, RECT* rectSrc, RECT* rectDest )
{
	BITMAPINFOHEADER* pBmInfo;
	char *pBmBytes, *pDest;

	unsigned curr_x, curr_y; /* used to indicate current iteration */
	unsigned srcwidth, srcheight; /* derived from source rectangle */
	unsigned limit_x, limit_y;
	unsigned alignment_tweak;	/* must tweak the width due to DWORD aligned data */

	/* NOTE: This routine cannot be highly optimised because source rectangles do not
		have to be word aligned although non-edge blocks can still be copied using
		LDM/STM instructions */

	/* Takes a pointer to an (8-bpp Windows DIB image),
		x and y are the byte no's from left and top */

	/* Strip off header and return if invalid i.e. not BM */
	if( pBmFile->bfType != 0x4D42 ) return 0;

	pBmInfo = (BITMAPINFOHEADER*)((char*)pBmFile+sizeof(BITMAPFILEHEADER));

	/* check header for valid formats, currently only 8 bit */
	if( pBmInfo->biBitCount != 8 ) return 0;

	pBmBytes = (char*)((char*)pBmFile+sizeof(BITMAPFILEHEADER)+pBmFile->bfOffBits-14);
	//pBmBytes = (char*)((char*)pBmFile+sizeof(BITMAPFILEHEADER)+pBmFile->bfOffBits-32);

	/* Dimensions can be grabbed from pBmInfo->biWidth, pBmInfo->biHeight */
	/* Draw the image, assuming DIB is bottom-up so we can just draw
		going up from the base display pointer */

	pDest = (char*)DISPLAY_PTR +
				rectDest->top * BYTES_PER_LINE + rectDest->left;

	/* set up loop limits from source rect; -1 indicates use of full bitmap as source */

	if( rectSrc->left != -1 ) {
		srcwidth = rectSrc->right - rectSrc->left;
		srcheight = rectSrc->bottom - rectSrc->top;

		limit_y = MIN( pBmInfo->biHeight, srcheight );
		limit_x = MIN( pBmInfo->biWidth, srcwidth );

		/* adjust byte pointer based on source rect */
		pBmBytes += rectSrc->left;
	} else {
		limit_y = pBmInfo->biHeight;
		limit_x = pBmInfo->biWidth;

		srcwidth = pBmInfo->biWidth;
		srcheight = pBmInfo->biHeight;
	}

	// source bitmap alignment tweak
	alignment_tweak = 4 - pBmInfo->biWidth % 4;
	if( alignment_tweak == 4 ) alignment_tweak = 0;

	for( curr_y = 0; curr_y < limit_y; curr_y++ ) {
		for( curr_x = 0; curr_x < limit_x; curr_x++ ) {
			*pDest = *pBmBytes++;
			pDest++;
		}

		/* adjust source pointer to skip any bytes excluded by low x limit
			assuming bitmap width is greater than or equal to source rectangle width. */
		pBmBytes = pBmBytes + pBmInfo->biWidth - limit_x + alignment_tweak;

		/* adjust destination pointer to skip to next line */
		pDest = pDest + BYTES_PER_LINE - limit_x;
	}

	return 1;
}

unsigned random( unsigned min, unsigned max )
{
	return rand() % (max-min+1) + min;
}

/* higher-level drawing functions */

void __inline drawCharXY( char c, RECT* rectDest )
{
	/* Set up a source rectangle and draw part of the chars image */
	/* calculate offset */
	RECT rectSrc;

	rectSrc.left = (c-32)*CHAR_WIDTH;
	rectSrc.top = 0;
	rectSrc.right = rectSrc.left + CHAR_WIDTH;
	rectSrc.bottom = CHAR_HEIGHT;

	drawSpriteXY( &chars, &rectSrc, rectDest );
}

void __inline drawStringXY( char* string, RECT* rectDest )
{
	/* loop through, incrementing positions and displaying characters */
	unsigned i;
	unsigned max_i = strlen( string );
	RECT newRect;

	newRect = *rectDest;

	for( i = 0; i < max_i; i++ ) {
		drawCharXY( *(string+i), &newRect );
		newRect.left += CHAR_WIDTH;
	}
}

void __inline scrollUp( unsigned lines )
{

	/* copy bytes 'up' in memory by specified amount -
		prime candidate for load/store multiple instruction optimisation */
	unsigned no_bytes = lines * BYTES_PER_LINE;
	unsigned no_blocks, no_bytes_left, temp_word;

	char *pSrc, *pDst, *pTmp;

	pDst = (char*)DISPLAY_PTR + BYTES_PER_LINE * getPixelsY();
	pSrc = pDst - no_bytes;

	// divide number of bytes by 4 (words) then 8 (blocks)
	no_blocks = ((unsigned)pSrc - DISPLAY_PTR) / 32 - 1;
	no_bytes_left = ((unsigned)pSrc - DISPLAY_PTR) - (no_blocks+1) * 32;

#ifdef FAST_DRAW

	__asm {
		// copy as much as possible using load/store multiple
		
		// put no of words to copy into d0
		// read and write data until
		// words left on line < no. words
loop1:
		LDMDA	pSrc!, {r4-r11}
		STMDA   pDst!, {r4-r11}
		SUBS no_blocks, no_blocks, #1
		BGE loop1

		// copy any bytes left over, if any
		CMP no_bytes_left, #0
		BLE fill

loop2:
		LDRB	temp_word, [pSrc]
		SUB pSrc, pSrc, #1
		STRB temp_word, [pDst]
		SUB pDst, pDst, #1
		SUBS no_bytes_left, no_bytes_left, #1
		BGE loop2

fill:
	}

#else

	/* keep copying till source hits bottom of display memory */
	while( pSrc >= (char*)DISPLAY_PTR ) {
		*pDst-- = *pSrc--;
	}

#endif

	/* blank off lower region with background color */
	pSrc = (char*)DISPLAY_PTR;
	pTmp = (char*)DISPLAY_PTR + no_bytes;
	while( pSrc < pTmp ) *pSrc++ = backcolor;
}

/* Keyboard/interrupt support */

void __irq myIRQhandler(void)
{
	int code = *((unsigned*)KB_CSR) & 0xFF;

	/* Ignore keyup events and characters not handled by fputc */
	if( code < 127 ) {
		/* indicate key to fgetc */
		keyflag = code;
	}

	/* clear interupt by writing to KB_ISR */
	*((unsigned*)KB_ISR) |= KB_RDRF;
}

unsigned Install_Handler( unsigned routine, unsigned *vector )
{
	unsigned vec, oldvec;
	vec = ((routine - (unsigned)vector - 0x8) >> 2 );
	vec = 0xea000000 | vec;
	oldvec = *vector;
	*vector = vec;
	return (oldvec);
}

__inline void enable_IRQ(void)
{
  int tmp;
  __asm
  {
    MRS tmp, CPSR
    BIC tmp, tmp, #0x80
    MSR CPSR_c, tmp
  }
}

/* Functions retargeted from C library
	prevents call to the semihosted function */

int fputc(int ch, FILE *f)
{	
	// TODO: handle arrow, enter and return keys, newline/CR
	if( ch == 13 || ch == 10 ) {	// CR
		// TODO: print a load of blanks up to the end of the line
		curr_pos.left = 0;
		curr_pos.top -= CHAR_HEIGHT;
	}

	// backspace
	if( ch == 8 ) {
		// head backwards ONLY UP TO THE EDGE
		curr_pos.left -= CHAR_WIDTH;
		if( curr_pos.left < 0 ) curr_pos.left = 0;

		// draw a blank where you are
		drawCharXY( ' ', &curr_pos );
	}

	// check if needs scrolling
	if( curr_pos.top < 0 ) {
		curr_pos.top += CHAR_HEIGHT;
		scrollUp( CHAR_HEIGHT );
	}

	// make a call to drawCharXY
	if( ch >= 32 ) {
		drawCharXY( ch, &curr_pos );

		curr_pos.left += CHAR_WIDTH;
		if( curr_pos.left > getPixelsX() - CHAR_WIDTH ) {
			curr_pos.left = 0;
			curr_pos.top -= CHAR_HEIGHT;
		}
	}

  return ch;
}

int fgetc(FILE *f)
{
	int result;
	/* wait for a keyboard interrupt and return next keystroke */
	while( !keyflag ) {}

	result = keyflag;
	keyflag = 0;

	if( getc_echo )
		putchar( result );

	return result;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -