nya
No notes
Syntax:
C
/* ============================================================================ 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; }