final verion

This commit is contained in:
feng-arch 2024-10-30 17:34:54 +08:00
parent 4957d76dee
commit 7989548b8d
4 changed files with 293 additions and 184 deletions

View File

@ -21,7 +21,7 @@ clobber: clean
rm -f *.bak
rm -f *.tmp
rm -f *.o
rm -f *.obj
rm -f core
# Phony targets
.PHONY: all clean clobber

View File

@ -17,8 +17,8 @@
int read_asm_file(char *filename, char program[ROWS][COLS]) {
FILE *file = fopen(filename, "r");
if (!file) {
printf("Error opening file %s\n", filename);
return -1;
printf("error: read_asm_file failed\n");
return 2;
}
int line_num = 0;
while (fgets(program[line_num], COLS, file) != NULL && line_num < ROWS) {
@ -50,7 +50,7 @@ int read_asm_file(char *filename, char program[ROWS][COLS]) {
line_num++;
}
fclose(file);
return line_num;
return 0;
}
int parse_instruction(char *instr, char *instr_bin_str) {
@ -66,7 +66,8 @@ int parse_instruction(char *instr, char *instr_bin_str) {
char *token = strtok(instr_copy, " ,\t");
if (token == NULL) {
// Empty or invalid instruction
return -1;
printf("error: parse_instruction failed\n");
return 3;
}
to_uppercase(token);
if (strcmp(token, "ADD") == 0) {
@ -86,22 +87,21 @@ int parse_instruction(char *instr, char *instr_bin_str) {
}
// Add other instructions here
else {
printf("Unknown instruction: %s\n", token);
return -1;
printf("error: parse_instruction failed\n");
return 3;
}
}
int parse_reg(char *reg_str) {
if (reg_str[0] != 'R' && reg_str[0] != 'r') {
printf("Invalid register: %s\n", reg_str);
return -1;
int parse_reg(char reg_num, char *instr_bin_str) {
if (reg_num < '0' || reg_num > '7') {
printf("error: parse_reg failed\n");
return 5;
}
int reg_num = atoi(&reg_str[1]);
if (reg_num < 0 || reg_num > 7) {
printf("Invalid register number: %d\n", reg_num);
return -1;
}
return reg_num;
int reg = reg_num - '0';
char bin_str[4];
int_to_bin_str(reg, 3, bin_str);
strcat(instr_bin_str, bin_str);
return 0;
}
void int_to_bin_str(int num, int bits, char *bin_str) {
@ -121,197 +121,306 @@ void to_uppercase(char *str) {
int parse_add(char *instr, char *instr_bin_str) {
// Instruction format: ADD Rd, Rs, Rt
// Opcode: 0001
char opcode[] = "0001";
char ddd[4], sss[4], ttt[4];
strcpy(instr_bin_str, "0001"); // Opcode
// Tokenize the instruction to get registers
char instr_copy[COLS];
strcpy(instr_copy, instr);
char *token = strtok(instr_copy, " ,\t"); // Skip 'ADD'
token = strtok(NULL, " ,\t"); // Rd
if (token == NULL) return -1;
int rd = parse_reg(token);
if (token == NULL) {
printf("error: parse_add() failed\n");
return 4;
}
char rd_num = token[1]; // Assuming 'R' is at token[0]
int ret = parse_reg(rd_num, instr_bin_str); // Rd
if (ret != 0) {
printf("error: parse_add() failed\n");
return 4;
}
token = strtok(NULL, " ,\t"); // Rs
if (token == NULL) return -1;
int rs = parse_reg(token);
if (token == NULL) {
printf("error: parse_add() failed\n");
return 4;
}
char rs_num = token[1];
ret = parse_reg(rs_num, instr_bin_str); // Rs
if (ret != 0) {
printf("error: parse_add() failed\n");
return 4;
}
strcat(instr_bin_str, "000"); // Sub-opcode for ADD
token = strtok(NULL, " ,\t"); // Rt
if (token == NULL) return -1;
int rt = parse_reg(token);
if (rd < 0 || rs < 0 || rt < 0) return -1;
// Convert rd, rs, rt to 3-bit binary strings
int_to_bin_str(rd, 3, ddd);
int_to_bin_str(rs, 3, sss);
int_to_bin_str(rt, 3, ttt);
// Build the binary instruction string
sprintf(instr_bin_str, "%s%s%s000%s", opcode, ddd, sss, ttt);
return 1;
if (token == NULL) {
printf("error: parse_add() failed\n");
return 4;
}
char rt_num = token[1];
ret = parse_reg(rt_num, instr_bin_str); // Rt
if (ret != 0) {
printf("error: parse_add() failed\n");
return 4;
}
return 0;
}
int parse_mul(char *instr, char *instr_bin_str) {
// Instruction format: MUL Rd, Rs, Rt
// Opcode: 0001
char opcode[] = "0001";
char ddd[4], sss[4], ttt[4];
strcpy(instr_bin_str, "0001"); // Opcode
// Tokenize the instruction to get registers
char instr_copy[COLS];
strcpy(instr_copy, instr);
char *token = strtok(instr_copy, " ,\t"); // Skip 'MUL'
token = strtok(NULL, " ,\t"); // Rd
if (token == NULL) return -1;
int rd = parse_reg(token);
if (token == NULL) {
printf("error: parse_mul() failed\n");
return 4;
}
char rd_num = token[1];
int ret = parse_reg(rd_num, instr_bin_str); // Rd
if (ret != 0) {
printf("error: parse_mul() failed\n");
return 4;
}
token = strtok(NULL, " ,\t"); // Rs
if (token == NULL) return -1;
int rs = parse_reg(token);
if (token == NULL) {
printf("error: parse_mul() failed\n");
return 4;
}
char rs_num = token[1];
ret = parse_reg(rs_num, instr_bin_str); // Rs
if (ret != 0) {
printf("error: parse_mul() failed\n");
return 4;
}
strcat(instr_bin_str, "001"); // Sub-opcode for MUL
token = strtok(NULL, " ,\t"); // Rt
if (token == NULL) return -1;
int rt = parse_reg(token);
if (rd < 0 || rs < 0 || rt < 0) return -1;
// Convert rd, rs, rt to 3-bit binary strings
int_to_bin_str(rd, 3, ddd);
int_to_bin_str(rs, 3, sss);
int_to_bin_str(rt, 3, ttt);
// Build the binary instruction string
sprintf(instr_bin_str, "%s%s%s001%s", opcode, ddd, sss, ttt);
return 1;
if (token == NULL) {
printf("error: parse_mul() failed\n");
return 4;
}
char rt_num = token[1];
ret = parse_reg(rt_num, instr_bin_str); // Rt
if (ret != 0) {
printf("error: parse_mul() failed\n");
return 4;
}
return 0;
}
int parse_sub(char *instr, char *instr_bin_str) {
// Instruction format: SUB Rd, Rs, Rt
// Opcode: 0001
char opcode[] = "0001";
char ddd[4], sss[4], ttt[4];
// Tokenize the instruction to get registers
// Similar to parse_add, with sub-opcode '010'
strcpy(instr_bin_str, "0001"); // Opcode
char instr_copy[COLS];
strcpy(instr_copy, instr);
char *token = strtok(instr_copy, " ,\t"); // Skip 'SUB'
token = strtok(NULL, " ,\t"); // Rd
if (token == NULL) return -1;
int rd = parse_reg(token);
if (token == NULL) {
printf("error: parse_sub() failed\n");
return 4;
}
char rd_num = token[1];
int ret = parse_reg(rd_num, instr_bin_str); // Rd
if (ret != 0) {
printf("error: parse_sub() failed\n");
return 4;
}
token = strtok(NULL, " ,\t"); // Rs
if (token == NULL) return -1;
int rs = parse_reg(token);
if (token == NULL) {
printf("error: parse_sub() failed\n");
return 4;
}
char rs_num = token[1];
ret = parse_reg(rs_num, instr_bin_str); // Rs
if (ret != 0) {
printf("error: parse_sub() failed\n");
return 4;
}
strcat(instr_bin_str, "010"); // Sub-opcode for SUB
token = strtok(NULL, " ,\t"); // Rt
if (token == NULL) return -1;
int rt = parse_reg(token);
if (rd < 0 || rs < 0 || rt < 0) return -1;
// Convert rd, rs, rt to 3-bit binary strings
int_to_bin_str(rd, 3, ddd);
int_to_bin_str(rs, 3, sss);
int_to_bin_str(rt, 3, ttt);
// Build the binary instruction string
sprintf(instr_bin_str, "%s%s%s010%s", opcode, ddd, sss, ttt);
return 1;
if (token == NULL) {
printf("error: parse_sub() failed\n");
return 4;
}
char rt_num = token[1];
ret = parse_reg(rt_num, instr_bin_str); // Rt
if (ret != 0) {
printf("error: parse_sub() failed\n");
return 4;
}
return 0;
}
int parse_div(char *instr, char *instr_bin_str) {
// Instruction format: DIV Rd, Rs, Rt
// Opcode: 0001
char opcode[] = "0001";
char ddd[4], sss[4], ttt[4];
// Tokenize the instruction to get registers
// Similar to parse_add, with sub-opcode '011'
strcpy(instr_bin_str, "0001"); // Opcode
char instr_copy[COLS];
strcpy(instr_copy, instr);
char *token = strtok(instr_copy, " ,\t"); // Skip 'DIV'
token = strtok(NULL, " ,\t"); // Rd
if (token == NULL) return -1;
int rd = parse_reg(token);
if (token == NULL) {
printf("error: parse_div() failed\n");
return 4;
}
char rd_num = token[1];
int ret = parse_reg(rd_num, instr_bin_str); // Rd
if (ret != 0) {
printf("error: parse_div() failed\n");
return 4;
}
token = strtok(NULL, " ,\t"); // Rs
if (token == NULL) return -1;
int rs = parse_reg(token);
if (token == NULL) {
printf("error: parse_div() failed\n");
return 4;
}
char rs_num = token[1];
ret = parse_reg(rs_num, instr_bin_str); // Rs
if (ret != 0) {
printf("error: parse_div() failed\n");
return 4;
}
strcat(instr_bin_str, "011"); // Sub-opcode for DIV
token = strtok(NULL, " ,\t"); // Rt
if (token == NULL) return -1;
int rt = parse_reg(token);
if (rd < 0 || rs < 0 || rt < 0) return -1;
// Convert rd, rs, rt to 3-bit binary strings
int_to_bin_str(rd, 3, ddd);
int_to_bin_str(rs, 3, sss);
int_to_bin_str(rt, 3, ttt);
// Build the binary instruction string
sprintf(instr_bin_str, "%s%s%s011%s", opcode, ddd, sss, ttt);
return 1;
if (token == NULL) {
printf("error: parse_div() failed\n");
return 4;
}
char rt_num = token[1];
ret = parse_reg(rt_num, instr_bin_str); // Rt
if (ret != 0) {
printf("error: parse_div() failed\n");
return 4;
}
return 0;
}
int parse_and(char *instr, char *instr_bin_str) {
// Instruction format: AND Rd, Rs, Rt
// Opcode: 0101
char opcode[] = "0101";
char ddd[4], sss[4], ttt[4];
// Tokenize the instruction to get registers
// Opcode: 0101, sub-opcode '000'
strcpy(instr_bin_str, "0101"); // Opcode
char instr_copy[COLS];
strcpy(instr_copy, instr);
char *token = strtok(instr_copy, " ,\t"); // Skip 'AND'
token = strtok(NULL, " ,\t"); // Rd
if (token == NULL) return -1;
int rd = parse_reg(token);
if (token == NULL) {
printf("error: parse_and() failed\n");
return 4;
}
char rd_num = token[1];
int ret = parse_reg(rd_num, instr_bin_str); // Rd
if (ret != 0) {
printf("error: parse_and() failed\n");
return 4;
}
token = strtok(NULL, " ,\t"); // Rs
if (token == NULL) return -1;
int rs = parse_reg(token);
if (token == NULL) {
printf("error: parse_and() failed\n");
return 4;
}
char rs_num = token[1];
ret = parse_reg(rs_num, instr_bin_str); // Rs
if (ret != 0) {
printf("error: parse_and() failed\n");
return 4;
}
strcat(instr_bin_str, "000"); // Sub-opcode for AND
token = strtok(NULL, " ,\t"); // Rt
if (token == NULL) return -1;
int rt = parse_reg(token);
if (rd < 0 || rs < 0 || rt < 0) return -1;
// Convert rd, rs, rt to 3-bit binary strings
int_to_bin_str(rd, 3, ddd);
int_to_bin_str(rs, 3, sss);
int_to_bin_str(rt, 3, ttt);
// Build the binary instruction string
sprintf(instr_bin_str, "%s%s%s000%s", opcode, ddd, sss, ttt);
return 1;
if (token == NULL) {
printf("error: parse_and() failed\n");
return 4;
}
char rt_num = token[1];
ret = parse_reg(rt_num, instr_bin_str); // Rt
if (ret != 0) {
printf("error: parse_and() failed\n");
return 4;
}
return 0;
}
int parse_or(char *instr, char *instr_bin_str) {
// Instruction format: OR Rd, Rs, Rt
// Opcode: 0101
char opcode[] = "0101";
char ddd[4], sss[4], ttt[4];
// Tokenize the instruction to get registers
// Opcode: 0101, sub-opcode '010'
strcpy(instr_bin_str, "0101"); // Opcode
char instr_copy[COLS];
strcpy(instr_copy, instr);
char *token = strtok(instr_copy, " ,\t"); // Skip 'OR'
token = strtok(NULL, " ,\t"); // Rd
if (token == NULL) return -1;
int rd = parse_reg(token);
if (token == NULL) {
printf("error: parse_or() failed\n");
return 4;
}
char rd_num = token[1];
int ret = parse_reg(rd_num, instr_bin_str); // Rd
if (ret != 0) {
printf("error: parse_or() failed\n");
return 4;
}
token = strtok(NULL, " ,\t"); // Rs
if (token == NULL) return -1;
int rs = parse_reg(token);
if (token == NULL) {
printf("error: parse_or() failed\n");
return 4;
}
char rs_num = token[1];
ret = parse_reg(rs_num, instr_bin_str); // Rs
if (ret != 0) {
printf("error: parse_or() failed\n");
return 4;
}
strcat(instr_bin_str, "010"); // Sub-opcode for OR
token = strtok(NULL, " ,\t"); // Rt
if (token == NULL) return -1;
int rt = parse_reg(token);
if (rd < 0 || rs < 0 || rt < 0) return -1;
// Convert rd, rs, rt to 3-bit binary strings
int_to_bin_str(rd, 3, ddd);
int_to_bin_str(rs, 3, sss);
int_to_bin_str(rt, 3, ttt);
// Build the binary instruction string
sprintf(instr_bin_str, "%s%s%s010%s", opcode, ddd, sss, ttt);
return 1;
if (token == NULL) {
printf("error: parse_or() failed\n");
return 4;
}
char rt_num = token[1];
ret = parse_reg(rt_num, instr_bin_str); // Rt
if (ret != 0) {
printf("error: parse_or() failed\n");
return 4;
}
return 0;
}
int parse_xor(char *instr, char *instr_bin_str) {
// Instruction format: XOR Rd, Rs, Rt
// Opcode: 0101
char opcode[] = "0101";
char ddd[4], sss[4], ttt[4];
// Tokenize the instruction to get registers
// Opcode: 0101, sub-opcode '011'
strcpy(instr_bin_str, "0101"); // Opcode
char instr_copy[COLS];
strcpy(instr_copy, instr);
char *token = strtok(instr_copy, " ,\t"); // Skip 'XOR'
token = strtok(NULL, " ,\t"); // Rd
if (token == NULL) return -1;
int rd = parse_reg(token);
if (token == NULL) {
printf("error: parse_xor() failed\n");
return 4;
}
char rd_num = token[1];
int ret = parse_reg(rd_num, instr_bin_str); // Rd
if (ret != 0) {
printf("error: parse_xor() failed\n");
return 4;
}
token = strtok(NULL, " ,\t"); // Rs
if (token == NULL) return -1;
int rs = parse_reg(token);
if (token == NULL) {
printf("error: parse_xor() failed\n");
return 4;
}
char rs_num = token[1];
ret = parse_reg(rs_num, instr_bin_str); // Rs
if (ret != 0) {
printf("error: parse_xor() failed\n");
return 4;
}
strcat(instr_bin_str, "011"); // Sub-opcode for XOR
token = strtok(NULL, " ,\t"); // Rt
if (token == NULL) return -1;
int rt = parse_reg(token);
if (rd < 0 || rs < 0 || rt < 0) return -1;
// Convert rd, rs, rt to 3-bit binary strings
int_to_bin_str(rd, 3, ddd);
int_to_bin_str(rs, 3, sss);
int_to_bin_str(rt, 3, ttt);
// Build the binary instruction string
sprintf(instr_bin_str, "%s%s%s011%s", opcode, ddd, sss, ttt);
return 1;
if (token == NULL) {
printf("error: parse_xor() failed\n");
return 4;
}
char rt_num = token[1];
ret = parse_reg(rt_num, instr_bin_str); // Rt
if (ret != 0) {
printf("error: parse_xor() failed\n");
return 4;
}
return 0;
}
unsigned short int str_to_bin(char *instr_bin_str) {
@ -322,8 +431,8 @@ unsigned short int str_to_bin(char *instr_bin_str) {
result |= 1;
} else if (instr_bin_str[i] != '0') {
// Invalid character
printf("Invalid binary string: %s\n", instr_bin_str);
return 0;
printf("error: str_to_bin failed\n");
return 6;
}
}
return result;
@ -332,8 +441,8 @@ unsigned short int str_to_bin(char *instr_bin_str) {
int write_obj_file(char *filename, unsigned short int program_bin[ROWS], int instr_count) {
FILE *file = fopen(filename, "wb");
if (!file) {
printf("Error opening file %s for writing\n", filename);
return -1;
printf("error: write_obj_file failed\n");
return 7;
}
// Write the code header: xCADE, address (start at 0), n (instr_count)
unsigned short int header[3];
@ -346,5 +455,3 @@ int write_obj_file(char *filename, unsigned short int program_bin[ROWS], int ins
fclose(file);
return 0;
}
/* to do - implement all the functions in asm_parser.h */

View File

@ -19,7 +19,7 @@
int read_asm_file(char *filename, char program[ROWS][COLS]);
int parse_instruction(char *instr, char *instr_bin_str);
int parse_reg(char *reg_str);
int parse_reg(char reg_num, char *instr_bin_str);
int parse_add(char *instr, char *instr_bin_str);
int parse_mul(char *instr, char *instr_bin_str);
int parse_sub(char *instr, char *instr_bin_str);

View File

@ -24,25 +24,28 @@ int main(int argc, char **argv) {
char program_bin_str[ROWS][17]; // instructions converted to a binary string
unsigned short int program_bin[ROWS]; // instructions in binary (HEX)
int num_lines = read_asm_file(filename, program);
if (num_lines < 0) {
return 1;
if (num_lines != 0) {
return num_lines; // Return error code from read_asm_file
}
int instr_count = 0;
for (int i = 0; i < num_lines; i++) {
for (int i = 0; i < ROWS && program[i][0] != '\0'; i++) {
char *line = program[i];
char instr_bin_str[17];
char instr_bin_str[17] = {0};
int ret = parse_instruction(line, instr_bin_str);
if (ret == 1) {
if (ret == 0) {
strcpy(program_bin_str[instr_count], instr_bin_str);
program_bin[instr_count] = str_to_bin(instr_bin_str);
unsigned short int bin = str_to_bin(instr_bin_str);
if (bin == 6) { // Error code from str_to_bin
printf("Error on line %d: %s\n", i + 1, line);
return i + 1;
}
program_bin[instr_count] = bin;
instr_count++;
} else if (ret == 0) {
// Skip empty or comment line
continue;
} else {
printf("Error parsing line %d: %s\n", i + 1, line);
return 1;
} else if (ret == 3) {
printf("Error on line %d: %s\n", i + 1, line);
return i + 1;
}
// ret == 0 means successful parsing
}
// Write the object file
char obj_filename[256];
@ -54,9 +57,8 @@ int main(int argc, char **argv) {
strcat(obj_filename, ".obj");
}
int ret = write_obj_file(obj_filename, program_bin, instr_count);
if (ret < 0) {
printf("Error writing object file\n");
return 1;
if (ret != 0) {
return ret; // Return error code from write_obj_file
}
printf("Successfully assembled %s to %s\n", filename, obj_filename);
return 0;