nya

by nya on December 24th, 2009
No notes
Syntax: C
Show lines - Hide lines - Show in textbox - Download
/*
 ============================================================================
 Name        : RiscCoreAsm.c
 Author      : kirka
 Version     : 0.01
 Copyright   : Your copyright notice
 Description : Custom assembler for custom risk-like architecture
 ============================================================================
 */
#include "string/LangString.h"
//#include "hashtable/HashTable<String,VoidPtr>.h"
#include "RiscCoreAsm.h"
 
/*===========================================================================*/
//IO and routines
 
LangInt CreateNewFile(const char* FileName) {
	//Open file using standard low level file interface indepndent from format
	printf("[Opening file at \"%s\"]\n", FileName);
 
	LangInt FileHandle = open( FileName, O_WRONLY | O_TRUNC | O_CREAT, S_IRWXO);
	//Check if file opened successfully
	if( FileHandle < 0) {
		printf("[File opening error: \"%s\"]\n", strerror( errno ));
		exit( -1 );
	} else {
		printf("[Got file descriptor %i]\n", FileHandle);
		return FileHandle;
	}
}
 
/*===========================================================================*/
//Lexer
typedef struct AsmLexer {
	//System and File-specific data
	LangUint LineNum;
	LangInt FileHandle;
	char current;
	bool TokenBegan;
	LangUint BufferIndex;
	LangUint BufferSize;
 
	//Current lexeme Data
	LangByte TokType;
	char* TokBuffer;
} AsmLexer;
 
AsmLexer* AsmLex_Create( const char* FileName ) {
	//Allocate space for structure
	AsmLexer* inst = calloc( 1, sizeof(AsmLexer) );
	assert( inst != NULL, "Fatal error: malloc() returns NULL" );
	inst->FileHandle = CreateNewFile( FileName );
	inst->LineNum = 0;
	inst->current = ' ';
	inst->TokenBegan = 0;
 
	//Allocate databuffer
	inst->TokBuffer = calloc( LEXER_BUFSIZE , 1 );
	inst->BufferIndex = 0;
	inst->BufferSize = LEXER_BUFSIZE;
 
	//Return created instance
	return inst;
}
 
void AsmLex_ReadChar(AsmLexer* self) {
	//Try to read 1 byte, and if not suceeded die with error message
	if ( read(self->FileHandle, &(self->current), 1) != 1 ) {
		printf("[File reading error: \"%s\"]\n", strerror( errno ));
		exit( -1 );
	}
}
 
void AsmLex_SaveChar(AsmLexer* self, char data) {
	//Check if there is no buffer overflow
	if( self->BufferIndex == self->BufferSize ) {
		printf("[fatal error: lexer buffer overflow]\n"); 
	} else {
		self->TokBuffer[ self->BufferIndex ] = data;
		self->BufferIndex += 1;
	}
}
 
void AsmLex_CleanBuffer(AsmLexer* self) {
	self->BufferIndex = 0;
}
 
bool Macro_Func whitespace( char c ) {
	return ( c == ' ' || c == '\t' || c == '\n' );
}
 
bool Macro_Func alphanum( char c ) {
	return (
		(c >= 'a' && c <= 'z') ||
		(c >= 'A' && c <= 'Z') ||
		(c >= '0' && c <= '9')
	);
 
}
 
void AsmLex_GetNext(AsmLexer* self) {
	switch ( self->current ) {
	case '\n':
	case '\t':
	case  ' ':
	case '\0': {
		if( self->TokenBegan ) {
			self->TokenBegan = 0;
			AsmLex_SaveChar(self, '\0');
			AsmLex_ReadChar(self);
			return;
		} else {
			AsmLex_ReadChar(self);
			break;
		}
	}
 
	case 'A' ... 'Z':
	case 'a' ... 'z':
	case '0' ... '9': {
		if( self->TokenBegan ) {
			AsmLex_SaveChar(self, self->current);
			AsmLex_ReadChar(self);
			break;
		} else {
			self->TokenBegan = 1;
			self->TokType = TK_ALNUM;
			AsmLex_SaveChar(self, self->current);
			AsmLex_ReadChar(self);
			break;
		}
	}
 
	case EOF:
		if( self->TokenBegan ) {
			self->TokenBegan = 0;
			return;
		} else {
			self->TokType = TK_EOF;
			return;
		}
 
	default:
		printf("[Unexpected Token: %c]", self->current);
		exit(-1);
	}
}
/*===========================================================================*/
//Parser
 
void assemble( const char* SrcFile,
			  const char* DstFile,
			  LangByte OutFormat ) {
 
 
}
 
/*===========================================================================*/
//Code Buffer
 
//Assembler code buffer structure
typedef struct AsmCodeBuffer {
	LangUint LastFreePos;
	LangUint BufferSize;
	void* buffer;
} AsmCodeBuffer;
 
//Return pointer to new AsmCodeBuffer object
Macro_Func AsmCodeBuffer* CodeBuf_Create() {
	//Allocate space for structure
	AsmCodeBuffer* inst = calloc(1, sizeof(AsmCodeBuffer));
	assert(inst != NULL, "Fatal error: malloc() returns NULL");
	//Initialise structure's variables
	inst->LastFreePos = 0;
	inst->BufferSize = BUF_STARTSIZE;
	//And it's code buffer
	inst->buffer = calloc( BUF_STARTSIZE, sizeof(MachineDWord) );
	assert(inst->buffer != NULL, "Fatal error: malloc() returns NULL, probably not enough virtual memory");
	//Return created object
	return inst;
}
 
 
//TODO: save to file, clean mess, decide which strings to use
void CodeBuf_SaveToBinFile(AsmCodeBuffer* self, int FileHandle) {
	//Write data to file
	printf("[Saving: %u bytes to file %i]\n", self->LastFreePos, FileHandle);
	LangInt written = write(FileHandle, self->buffer, self->LastFreePos*4);
	printf("[Written %i bytes]\n", written);
}
 
#define STRBUF_SIZE 8
void CodeBuf_SaveToTxtHexFile(AsmCodeBuffer* self, int FileHandle) {
	char BufString[ STRBUF_SIZE ];
 
	LangUint i;
	LangUint written;
	LangUint TotalWritten;
	for(i = 0; i < (self->LastFreePos)/4; i += 1) {
		sprintf( BufString, "%X\n", ((MachineDWord*) self->buffer)[ i*4 ] );
		//Actually write data to file
		written = write( FileHandle, BufString, strlen(BufString));
		//Check if there was no IO error
		if( written != strlen(BufString) ) {
 
			printf("[Tried to write %u bytes, written %i bytes]\n",
				strlen(BufString),
				written);
 
			printf("[File writing error: \"%s\"]\n", strerror( errno ));
			exit( -1 );
		}
		//Add written bytes to total count
		TotalWritten += written;
	}
 
	printf("[Completed, %u bytes written]\n", TotalWritten);
}
 
#define VERILOG_MEMNAME_STR
void CodeBuf_SaveToVerilogFile(AsmCodeBuffer* self, int FileHandle) {
	char BufString[ STRBUF_SIZE ];
 
	LangUint i;
	LangUint written;
	LangUint TotalWritten;
	for(i = 0; i < (self->LastFreePos)/4; i += 1) {
		sprintf( BufString, "VERILOG_MEMNAME_STR[%u] <= %X,\n", i, ((MachineDWord*) self->buffer)[ i ] );
		//Actually write data to file
 
		written = write( FileHandle, BufString, strlen(BufString));
		//Check if there was no IO error
		if( written != strlen(BufString) ) {
			printf("[File writing error: \"%s\", %u bytes written]\n",
				strerror( errno ),
				TotalWritten + written);
			exit( -1 );
		}
		//Add written bytes to total count
		TotalWritten += written;
	}
 
	printf("[Completed, %u bytes written]\n", TotalWritten);
}
 
void CodeBuf_PrintDbgInfo(AsmCodeBuffer* self) {
	printf("[AsmCodeBuffer at %p]\n", self);
	printf("[LastFreePos = %u]\n", self->LastFreePos);
	printf("[BufferSize = %u]\n", self->BufferSize);
	printf("[Buffer is located at %p]\n", self->buffer);
}
 
void CodeBuf_SaveToFile(AsmCodeBuffer* self, LangByte format, const char* FileName) {
	//Print debug data about CodeBuffer
	CodeBuf_PrintDbgInfo( self );
 
	//Create file where data will be saved; If already exists it's rewritten
	LangInt FileHandle = CreateNewFile( FileName );
 
	//Save data using function for given format
	switch( format ) {
	case FMT_BIN:
		CodeBuf_SaveToBinFile(self, FileHandle);
	case FMT_TXTHEX:
		CodeBuf_SaveToTxtHexFile(self, FileHandle);
	case FMT_VERILOG:
		CodeBuf_SaveToVerilogFile(self, FileHandle);
	}
 
	//Close file handle
	fsync( FileHandle );
	close( FileHandle );
 
}
 
//Check if we need grow buffer
Macro_Func bool CodeBuf_NeedsGrowing(AsmCodeBuffer* self) {
	return (self->LastFreePos == self->BufferSize);
}
 
//Grow buffer size by next power of 2, note that begininng width cannot equal zero
Macro_Func void CodeBuf_Grow(AsmCodeBuffer* self) {
	self->buffer = realloc(self->buffer, self->BufferSize * 2);
}
 
//Write instruction to code buffer
void CodeBuf_WriteInsn(AsmCodeBuffer* self, MachineDWord insn, LangByte InstSize) {
	if( CodeBuf_NeedsGrowing(self) ) {
		CodeBuf_Grow(self);
	}
	//Write to buffer of CodeBuffer structure, and increment size
	((MachineDWord*) self->buffer)[ self->LastFreePos ] = insn;
	self->LastFreePos += InstSize;
}
 
//Convert byte order, for double-word
MachineDWord Inst_DWord_TranslateLEtoBE(MachineDWord inst) {
	MachineDWord translated =
				((inst << 24) & 0xFF000000) |
				((inst << 8)  & 0x00FF0000)	|
				((inst >> 8)  & 0x0000FF00)	|
				((inst >> 24) & 0x000000FF)	;
	printf("[TRANSLATE: 0x%X]\n", translated);
	return translated;
}
 
//Get size of instruction in bytes (2 or 4)
LangByte Macro_Func Opcode_GetSize(LangByte opcode) {
#ifdef VARIABLE_INST_LENGTH
	switch(opcode) {
	case OP_LDI:
	case OP_ST:
	case OP_LD:
		return 4;
	default:
		return 2;
	}
#else
	return 4;
#endif
}
 
//Emit assembler instruction to code buffer
void CodeBuf_EmitInstruction(AsmCodeBuffer* CodeBuf,
	LangByte opcode,
	LangByte RegDst,
	LangByte RegSrc,
	MachineWord constant) {
		MachineDWord instruction = 0;	//Instruction being assembled
		//Check validity of arguments
		assert( opcode <= OPCODE_LAST, "Not valid opcode" );
		assert( RegDst < REG_NUM, "Not valid RegDst" );
		assert( RegDst < REG_NUM, "Not valid RegSrc" );
		assert( constant <= CONSTANT_MAX, "Constant overflow");
 
		//Calculate size of instruction
		LangByte InstSize = Opcode_GetSize( opcode );
 
		//Assemble parts of instruction into instruction
		instruction |= ((opcode & OPCODE_MASK) << (OPCODE_OFFSET));
		instruction |= ((RegDst & REG_ADDR_MASK) << (REG_DST_OFFSET));
		instruction |= ((RegSrc & REG_ADDR_MASK) << (REG_SRC_OFFSET));
		instruction |= (constant << (CONST_OFFSET));
 
		//Debug
		printf("[Assemble: OP=%i, RDST=%i, RSRC=%i, CNST=%i, INST=0x%x]\n",
				opcode,
				RegDst,
				RegSrc,
				constant,
				instruction);
 
		//Append instruction to buffer, translating it from Little-Endian to Big-Endian
		CodeBuf_WriteInsn(CodeBuf, instruction, InstSize);
}
 
/*===========================================================================*/
//Top level
 
int main(int argc, char** argv) {
	puts("[Starting system...]");
 
	//String* TestName = String_Create("out.bin");
	char TestName[] = "output.txt";
 
	AsmCodeBuffer* TestBuffer = CodeBuf_Create();
	CodeBuf_EmitInstruction(TestBuffer, OP_LDI, R1, R0, 0xAA);
	CodeBuf_EmitInstruction(TestBuffer, OP_LDI, R2, R0, 0xAA);
	CodeBuf_EmitInstruction(TestBuffer, OP_ADD, R1, R2, 0);
	CodeBuf_EmitInstruction(TestBuffer, OP_AND, R1, R2, 0);
	CodeBuf_EmitInstruction(TestBuffer, OP_JZ, R0, R0, 1);
	//CodeBuf_EmitInstruction(TestBuffer, 1, 2, 3, 0);
 
	//Inst_DWord_TranslateLEtoBE(0xDEADBEEF);
 
	CodeBuf_SaveToFile(TestBuffer, FMT_TXTHEX, TestName);
	return 0;
}

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS