Fix labels and jumps
This commit is contained in:
@@ -32,7 +32,7 @@ int lookupLabel(const char *name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add a label to the table
|
// Add a label to the table
|
||||||
int addLabel(const char *name, int address) {
|
int addLabel(const char *name, uint32_t address) {
|
||||||
if (labelCount >= MAX_LABELS) {
|
if (labelCount >= MAX_LABELS) {
|
||||||
fprintf(stderr, "Too many labels!\n");
|
fprintf(stderr, "Too many labels!\n");
|
||||||
return 1;
|
return 1;
|
||||||
@@ -316,139 +316,30 @@ void firstPass(const char *source) {
|
|||||||
continue;
|
continue;
|
||||||
strcpy(line, rest);
|
strcpy(line, rest);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// // Parse the mnemonic and operands.
|
// Parse the mnemonic and operands.
|
||||||
// char mnemonic[32], operand1[64], operand2[64], operand3[64];
|
char mnemonic[32], operand1[64], operand2[64], operand3[64];
|
||||||
// operand1[0] = '\0';
|
operand1[0] = '\0';
|
||||||
// operand2[0] = '\0';
|
operand2[0] = '\0';
|
||||||
// int tokenCount = sscanf(line, "%31s %63[^ ] %63[^ ] %63s",
|
sscanf(line, "%31s %63[^ ] %63[^ ] %63s",
|
||||||
// mnemonic, operand1, operand2, operand3);
|
mnemonic, operand1, operand2, operand3);
|
||||||
//
|
|
||||||
//
|
|
||||||
// // Use the mapper to get a base opcode.
|
// Use the mapper to get a base opcode.
|
||||||
// int baseOpcode = getOpcode(mnemonic);
|
int baseOpcode = getOpcode(mnemonic);
|
||||||
// if (baseOpcode == -1) {
|
if (baseOpcode == -1) {
|
||||||
// printf("Unknown instruction: %s\n", mnemonic);
|
printf("Unknown instruction: %s\n", mnemonic);
|
||||||
// continue;
|
continue;
|
||||||
// }
|
}
|
||||||
//
|
addr += CPU_INSTRUCTION_SIZE;
|
||||||
// int size = CPU_INSTRUCTION_SIZE; // Instruction size in bytes.
|
}
|
||||||
// if (baseOpcode == -2) {
|
|
||||||
// // MOV instruction requires further resolution.
|
|
||||||
// int resolvedOpcode = resolveMOV(operand1, operand2);
|
|
||||||
// if (resolvedOpcode == MOV_RN_IMM || resolvedOpcode == MOV_RN_RM) {
|
|
||||||
// size = 3; // opcode (1) + reg (1) + immediate or register (1)
|
|
||||||
// } else if (resolvedOpcode == MOV_RN_ADDR || resolvedOpcode == MOV_ADDR_RN) {
|
|
||||||
// size = 6; // opcode (1) + one operand as register (1) and one 32-bit address (4) [+ padding if needed]
|
|
||||||
// } else {
|
|
||||||
// size = 3; // fallback
|
|
||||||
// }
|
|
||||||
// } else if (baseOpcode < 0) {
|
|
||||||
// // Ambiguous instructions that use resolveALU.
|
|
||||||
// // For JMP and jump-bit instructions, the jump target is in operand1.
|
|
||||||
// if (baseOpcode == -11) {
|
|
||||||
// // JMP: if operand1 starts with '+' or '-', it's relative.
|
|
||||||
// if (operand1[0] == '+' || operand1[0] == '-') {
|
|
||||||
// // resolve as JMP_REL.
|
|
||||||
// int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
|
||||||
// size = 2; // opcode (1) + 1-byte relative offset (1)
|
|
||||||
// } else {
|
|
||||||
// int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
|
||||||
// size = 5; // opcode (1) + 32-bit absolute address (4)
|
|
||||||
// }
|
|
||||||
// } else if (baseOpcode == -14 || baseOpcode == -15) {
|
|
||||||
// // JMPBS or JMPBC (jump if bit set/clear)
|
|
||||||
// int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
|
||||||
// if (operand1[0] == 'R' || operand1[0] == 'r')
|
|
||||||
// size = 7; // opcode (1) + register (1) + bit (1) + 32-bit jump address (4)
|
|
||||||
// else
|
|
||||||
// size = 10; // opcode (1) + 32-bit memory address (4) + bit (1) + 32-bit jump address (4)
|
|
||||||
// } else {
|
|
||||||
// // For arithmetic ALU instructions and INC/DEC,
|
|
||||||
// // use operand2 to resolve.
|
|
||||||
// int resolvedOpcode = resolveALU(baseOpcode, operand2);
|
|
||||||
// switch (resolvedOpcode) {
|
|
||||||
// case ADD_RN_RM:
|
|
||||||
// case SUB_RN_RM:
|
|
||||||
// case MUL_RN_RM:
|
|
||||||
// case DIV_RN_RM:
|
|
||||||
// case MOD_RN_RM:
|
|
||||||
// case AND_RN_RM:
|
|
||||||
// case OR_RN_RM:
|
|
||||||
// case XOR_RN_RM:
|
|
||||||
// case ADD_RN_IMM:
|
|
||||||
// case SUB_RN_IMM:
|
|
||||||
// case MUL_RN_IMM:
|
|
||||||
// case DIV_RN_IMM:
|
|
||||||
// case MOD_RN_IMM:
|
|
||||||
// case AND_RN_IMM:
|
|
||||||
// case OR_RN_IMM:
|
|
||||||
// case XOR_RN_IMM:
|
|
||||||
// size = 3; // opcode (1) + register (1) + reg/immediate (1)
|
|
||||||
// break;
|
|
||||||
// case INC_RN:
|
|
||||||
// case DEC_RN:
|
|
||||||
// size = 2; // opcode (1) + register (1)
|
|
||||||
// break;
|
|
||||||
// case INC_ADDR:
|
|
||||||
// case DEC_ADDR:
|
|
||||||
// size = 5; // opcode (1) + 32-bit address (4)
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// size = 3;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// // Non-ambiguous instructions that have positive opcodes.
|
|
||||||
// // Use the mapping value (baseOpcode) directly.
|
|
||||||
// switch (baseOpcode) {
|
|
||||||
// case NOP:
|
|
||||||
// case BRK:
|
|
||||||
// case HLT:
|
|
||||||
// size = 1;
|
|
||||||
// break;
|
|
||||||
// case SWAP:
|
|
||||||
// case CMP:
|
|
||||||
// size = 3;
|
|
||||||
// break;
|
|
||||||
// case SWAPN:
|
|
||||||
// case NEG_RN:
|
|
||||||
// case NOT_RN:
|
|
||||||
// size = 2;
|
|
||||||
// break;
|
|
||||||
// case SHL_RN_IMM:
|
|
||||||
// case SHR_RN_IMM:
|
|
||||||
// case SAR_RN_IMM:
|
|
||||||
// size = 3;
|
|
||||||
// break;
|
|
||||||
// case JE:
|
|
||||||
// case JNE:
|
|
||||||
// case JG:
|
|
||||||
// case JL:
|
|
||||||
// case JGE:
|
|
||||||
// case JLE:
|
|
||||||
// case CALL:
|
|
||||||
// size = 5; // opcode (1) + 32-bit address (4)\n break;
|
|
||||||
// case RET:
|
|
||||||
// size = 1;
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// size = 3;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// addr += size;
|
|
||||||
// }
|
|
||||||
// return addr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// The second pass actually translates the assembly instructions to machine code.
|
// The second pass actually translates the assembly instructions to machine code.
|
||||||
// The machine code is written into the provided buffer. (It must be large enough.)
|
// The machine code is written into the provided buffer. (It must be large enough.)
|
||||||
//
|
//
|
||||||
int completePass(const char *source, CPU *cpu, bool erase) {
|
uint32_t completePass(const char *source, CPU *cpu, bool erase) {
|
||||||
if (erase) {
|
if (erase) {
|
||||||
memset(cpu->memory, 0, sizeof(cpu->memory));
|
memset(cpu->memory, 0, sizeof(cpu->memory));
|
||||||
memset(cpu->regs, 0, sizeof(cpu->regs));
|
memset(cpu->regs, 0, sizeof(cpu->regs));
|
||||||
@@ -488,8 +379,8 @@ int completePass(const char *source, CPU *cpu, bool erase) {
|
|||||||
// Parse mnemonic and up to three operands.
|
// Parse mnemonic and up to three operands.
|
||||||
char mnemonic[32], operand1[64], operand2[64], operand3[64];
|
char mnemonic[32], operand1[64], operand2[64], operand3[64];
|
||||||
mnemonic[0] = operand1[0] = operand2[0] = operand3[0] = '\0';
|
mnemonic[0] = operand1[0] = operand2[0] = operand3[0] = '\0';
|
||||||
int tokenCount = sscanf(line, "%31s %63[^ ] %63[^ ] %63s",
|
sscanf(line, "%31s %63[^ ] %63[^ ] %63s",
|
||||||
mnemonic, operand1, operand2, operand3);
|
mnemonic, operand1, operand2, operand3);
|
||||||
|
|
||||||
// (Optionally, you might trim each operand individually here.)
|
// (Optionally, you might trim each operand individually here.)
|
||||||
|
|
||||||
@@ -733,5 +624,6 @@ int completePass(const char *source, CPU *cpu, bool erase) {
|
|||||||
lineIndex++;
|
lineIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cpu->programEnd = addr;
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
@@ -24,7 +24,7 @@
|
|||||||
//
|
//
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[64];
|
char name[64];
|
||||||
int address; // address (in the output machine code)
|
uint32_t address; // address (in the output machine code)
|
||||||
} Label;
|
} Label;
|
||||||
|
|
||||||
extern Label labels[MAX_LABELS];
|
extern Label labels[MAX_LABELS];
|
||||||
@@ -43,7 +43,7 @@ void toLowerCase(char *string);
|
|||||||
int lookupLabel(const char *name);
|
int lookupLabel(const char *name);
|
||||||
|
|
||||||
// Add a label to the table
|
// Add a label to the table
|
||||||
int addLabel(const char *name, int address);
|
int addLabel(const char *name, uint32_t address);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Parse a register string (e.g., "R0", "R1", etc.) and return it's number.
|
// Parse a register string (e.g., "R0", "R1", etc.) and return it's number.
|
||||||
@@ -83,7 +83,7 @@ void firstPass(const char *source);
|
|||||||
// The second pass actually translates the assembly instructions to machine code.
|
// The second pass actually translates the assembly instructions to machine code.
|
||||||
// The machine code is written into the provided buffer. (It must be large enough.)
|
// The machine code is written into the provided buffer. (It must be large enough.)
|
||||||
//
|
//
|
||||||
int completePass(const char *input, CPU *cpu, bool erase);
|
uint32_t completePass(const char *input, CPU *cpu, bool erase);
|
||||||
|
|
||||||
|
|
||||||
#endif //RISCB_ASSEMBLER_H
|
#endif //RISCB_ASSEMBLER_H
|
||||||
|
39
cpu/core.c
39
cpu/core.c
@@ -9,7 +9,7 @@
|
|||||||
// Initialize CPU
|
// Initialize CPU
|
||||||
void init_cpu(CPU *cpu) {
|
void init_cpu(CPU *cpu) {
|
||||||
memset(cpu, 0, sizeof(CPU));
|
memset(cpu, 0, sizeof(CPU));
|
||||||
cpu->mode = CPU_MODE_HALTED;
|
cpu->mode = CPU_MODE_HALTED | CPU_MODE_SECOND;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function for setting flags in the CPU (here we assume bit0 is the Zero flag,
|
// Helper function for setting flags in the CPU (here we assume bit0 is the Zero flag,
|
||||||
@@ -27,7 +27,7 @@ void step(CPU *cpu) {
|
|||||||
if (cpu->mode & (CPU_MODE_HALTED | CPU_MODE_PAUSED | CPU_MODE_ERROR)) {
|
if (cpu->mode & (CPU_MODE_HALTED | CPU_MODE_PAUSED | CPU_MODE_ERROR)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (cpu->pc >= MEM_SIZE) {
|
if (cpu->pc >= MEM_SIZE || cpu->pc >= cpu->programEnd) {
|
||||||
if (cpu->mode | CPU_MODE_LOOP) {
|
if (cpu->mode | CPU_MODE_LOOP) {
|
||||||
cpu->pc = 0;
|
cpu->pc = 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -385,8 +385,11 @@ void step(CPU *cpu) {
|
|||||||
if (bit > 7) {
|
if (bit > 7) {
|
||||||
bit = 7;
|
bit = 7;
|
||||||
}
|
}
|
||||||
if (temp & (1 << bit))
|
if (temp & (1 << bit)) {
|
||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JMP_BIT_SET_ADDR: {
|
case JMP_BIT_SET_ADDR: {
|
||||||
@@ -400,8 +403,11 @@ void step(CPU *cpu) {
|
|||||||
bit = 7;
|
bit = 7;
|
||||||
}
|
}
|
||||||
newPC = read_address_argument(cpu);
|
newPC = read_address_argument(cpu);
|
||||||
if (read_mem(cpu, addrTemp) & (1 << bit))
|
if (read_mem(cpu, addrTemp) & (1 << bit)) {
|
||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,8 +415,11 @@ void step(CPU *cpu) {
|
|||||||
case JE: {
|
case JE: {
|
||||||
// Jump if equal (Zero flag set)
|
// Jump if equal (Zero flag set)
|
||||||
newPC = read_address_argument(cpu);
|
newPC = read_address_argument(cpu);
|
||||||
if (cpu->flags & CPU_FLAG_ZERO)
|
if (cpu->flags & CPU_FLAG_ZERO) {
|
||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,8 +432,11 @@ void step(CPU *cpu) {
|
|||||||
bit = 7;
|
bit = 7;
|
||||||
}
|
}
|
||||||
newPC = read_address_argument(cpu);
|
newPC = read_address_argument(cpu);
|
||||||
if (!(temp & (1 << bit)))
|
if (!(temp & (1 << bit))) {
|
||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,8 +448,11 @@ void step(CPU *cpu) {
|
|||||||
bit = 7;
|
bit = 7;
|
||||||
}
|
}
|
||||||
newPC = read_address_argument(cpu);
|
newPC = read_address_argument(cpu);
|
||||||
if (!(read_mem(cpu, addrTemp) & (1 << bit)))
|
if (!(read_mem(cpu, addrTemp) & (1 << bit))) {
|
||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -446,7 +461,9 @@ void step(CPU *cpu) {
|
|||||||
newPC = read_address_argument(cpu);
|
newPC = read_address_argument(cpu);
|
||||||
if (!(cpu->flags & CPU_FLAG_ZERO)) {
|
if (!(cpu->flags & CPU_FLAG_ZERO)) {
|
||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,7 +472,9 @@ void step(CPU *cpu) {
|
|||||||
newPC = read_address_argument(cpu);
|
newPC = read_address_argument(cpu);
|
||||||
if (!(cpu->flags & CPU_FLAG_NEGATIVE) && !(cpu->flags & CPU_FLAG_ZERO)) {
|
if (!(cpu->flags & CPU_FLAG_NEGATIVE) && !(cpu->flags & CPU_FLAG_ZERO)) {
|
||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,7 +483,9 @@ void step(CPU *cpu) {
|
|||||||
newPC = read_address_argument(cpu);
|
newPC = read_address_argument(cpu);
|
||||||
if (cpu->flags & CPU_FLAG_NEGATIVE) {
|
if (cpu->flags & CPU_FLAG_NEGATIVE) {
|
||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,7 +494,9 @@ void step(CPU *cpu) {
|
|||||||
newPC = read_address_argument(cpu);
|
newPC = read_address_argument(cpu);
|
||||||
if ((cpu->flags & CPU_FLAG_ZERO) || !(cpu->flags & CPU_FLAG_NEGATIVE)) {
|
if ((cpu->flags & CPU_FLAG_ZERO) || !(cpu->flags & CPU_FLAG_NEGATIVE)) {
|
||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +505,9 @@ void step(CPU *cpu) {
|
|||||||
newPC = read_address_argument(cpu);
|
newPC = read_address_argument(cpu);
|
||||||
if ((cpu->flags & CPU_FLAG_NEGATIVE) || (cpu->flags & CPU_FLAG_ZERO)) {
|
if ((cpu->flags & CPU_FLAG_NEGATIVE) || (cpu->flags & CPU_FLAG_ZERO)) {
|
||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -35,6 +35,7 @@ typedef struct {
|
|||||||
uint32_t pc; // Program counter
|
uint32_t pc; // Program counter
|
||||||
uint32_t stack_ptr; // Stack pointer
|
uint32_t stack_ptr; // Stack pointer
|
||||||
uint8_t flags; // Status flags
|
uint8_t flags; // Status flags
|
||||||
|
uint32_t programEnd;
|
||||||
uint8_t mode;
|
uint8_t mode;
|
||||||
uint32_t cycle;
|
uint32_t cycle;
|
||||||
} CPU;
|
} CPU;
|
||||||
|
Reference in New Issue
Block a user