Fix labels and jumps
This commit is contained in:
@@ -32,7 +32,7 @@ int lookupLabel(const char *name) {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
fprintf(stderr, "Too many labels!\n");
|
||||
return 1;
|
||||
@@ -316,139 +316,30 @@ void firstPass(const char *source) {
|
||||
continue;
|
||||
strcpy(line, rest);
|
||||
}
|
||||
}
|
||||
|
||||
// // Parse the mnemonic and operands.
|
||||
// char mnemonic[32], operand1[64], operand2[64], operand3[64];
|
||||
// operand1[0] = '\0';
|
||||
// operand2[0] = '\0';
|
||||
// int tokenCount = sscanf(line, "%31s %63[^ ] %63[^ ] %63s",
|
||||
// mnemonic, operand1, operand2, operand3);
|
||||
//
|
||||
//
|
||||
// // Use the mapper to get a base opcode.
|
||||
// int baseOpcode = getOpcode(mnemonic);
|
||||
// if (baseOpcode == -1) {
|
||||
// printf("Unknown instruction: %s\n", mnemonic);
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// 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;
|
||||
// Parse the mnemonic and operands.
|
||||
char mnemonic[32], operand1[64], operand2[64], operand3[64];
|
||||
operand1[0] = '\0';
|
||||
operand2[0] = '\0';
|
||||
sscanf(line, "%31s %63[^ ] %63[^ ] %63s",
|
||||
mnemonic, operand1, operand2, operand3);
|
||||
|
||||
|
||||
// Use the mapper to get a base opcode.
|
||||
int baseOpcode = getOpcode(mnemonic);
|
||||
if (baseOpcode == -1) {
|
||||
printf("Unknown instruction: %s\n", mnemonic);
|
||||
continue;
|
||||
}
|
||||
addr += CPU_INSTRUCTION_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 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.)
|
||||
//
|
||||
int completePass(const char *source, CPU *cpu, bool erase) {
|
||||
uint32_t completePass(const char *source, CPU *cpu, bool erase) {
|
||||
if (erase) {
|
||||
memset(cpu->memory, 0, sizeof(cpu->memory));
|
||||
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.
|
||||
char mnemonic[32], operand1[64], operand2[64], operand3[64];
|
||||
mnemonic[0] = operand1[0] = operand2[0] = operand3[0] = '\0';
|
||||
int tokenCount = sscanf(line, "%31s %63[^ ] %63[^ ] %63s",
|
||||
mnemonic, operand1, operand2, operand3);
|
||||
sscanf(line, "%31s %63[^ ] %63[^ ] %63s",
|
||||
mnemonic, operand1, operand2, operand3);
|
||||
|
||||
// (Optionally, you might trim each operand individually here.)
|
||||
|
||||
@@ -733,5 +624,6 @@ int completePass(const char *source, CPU *cpu, bool erase) {
|
||||
lineIndex++;
|
||||
}
|
||||
|
||||
cpu->programEnd = addr;
|
||||
return addr;
|
||||
}
|
@@ -24,7 +24,7 @@
|
||||
//
|
||||
typedef struct {
|
||||
char name[64];
|
||||
int address; // address (in the output machine code)
|
||||
uint32_t address; // address (in the output machine code)
|
||||
} Label;
|
||||
|
||||
extern Label labels[MAX_LABELS];
|
||||
@@ -43,7 +43,7 @@ void toLowerCase(char *string);
|
||||
int lookupLabel(const char *name);
|
||||
|
||||
// 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.
|
||||
@@ -83,7 +83,7 @@ void firstPass(const char *source);
|
||||
// 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.)
|
||||
//
|
||||
int completePass(const char *input, CPU *cpu, bool erase);
|
||||
uint32_t completePass(const char *input, CPU *cpu, bool erase);
|
||||
|
||||
|
||||
#endif //RISCB_ASSEMBLER_H
|
||||
|
39
cpu/core.c
39
cpu/core.c
@@ -9,7 +9,7 @@
|
||||
// Initialize CPU
|
||||
void init_cpu(CPU *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,
|
||||
@@ -27,7 +27,7 @@ void step(CPU *cpu) {
|
||||
if (cpu->mode & (CPU_MODE_HALTED | CPU_MODE_PAUSED | CPU_MODE_ERROR)) {
|
||||
return;
|
||||
}
|
||||
if (cpu->pc >= MEM_SIZE) {
|
||||
if (cpu->pc >= MEM_SIZE || cpu->pc >= cpu->programEnd) {
|
||||
if (cpu->mode | CPU_MODE_LOOP) {
|
||||
cpu->pc = 0;
|
||||
} else {
|
||||
@@ -385,8 +385,11 @@ void step(CPU *cpu) {
|
||||
if (bit > 7) {
|
||||
bit = 7;
|
||||
}
|
||||
if (temp & (1 << bit))
|
||||
if (temp & (1 << bit)) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
|
||||
case JMP_BIT_SET_ADDR: {
|
||||
@@ -400,8 +403,11 @@ void step(CPU *cpu) {
|
||||
bit = 7;
|
||||
}
|
||||
newPC = read_address_argument(cpu);
|
||||
if (read_mem(cpu, addrTemp) & (1 << bit))
|
||||
if (read_mem(cpu, addrTemp) & (1 << bit)) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -409,8 +415,11 @@ void step(CPU *cpu) {
|
||||
case JE: {
|
||||
// Jump if equal (Zero flag set)
|
||||
newPC = read_address_argument(cpu);
|
||||
if (cpu->flags & CPU_FLAG_ZERO)
|
||||
if (cpu->flags & CPU_FLAG_ZERO) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -423,8 +432,11 @@ void step(CPU *cpu) {
|
||||
bit = 7;
|
||||
}
|
||||
newPC = read_address_argument(cpu);
|
||||
if (!(temp & (1 << bit)))
|
||||
if (!(temp & (1 << bit))) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -436,8 +448,11 @@ void step(CPU *cpu) {
|
||||
bit = 7;
|
||||
}
|
||||
newPC = read_address_argument(cpu);
|
||||
if (!(read_mem(cpu, addrTemp) & (1 << bit)))
|
||||
if (!(read_mem(cpu, addrTemp) & (1 << bit))) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -446,7 +461,9 @@ void step(CPU *cpu) {
|
||||
newPC = read_address_argument(cpu);
|
||||
if (!(cpu->flags & CPU_FLAG_ZERO)) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -455,7 +472,9 @@ void step(CPU *cpu) {
|
||||
newPC = read_address_argument(cpu);
|
||||
if (!(cpu->flags & CPU_FLAG_NEGATIVE) && !(cpu->flags & CPU_FLAG_ZERO)) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -464,7 +483,9 @@ void step(CPU *cpu) {
|
||||
newPC = read_address_argument(cpu);
|
||||
if (cpu->flags & CPU_FLAG_NEGATIVE) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -473,7 +494,9 @@ void step(CPU *cpu) {
|
||||
newPC = read_address_argument(cpu);
|
||||
if ((cpu->flags & CPU_FLAG_ZERO) || !(cpu->flags & CPU_FLAG_NEGATIVE)) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -482,7 +505,9 @@ void step(CPU *cpu) {
|
||||
newPC = read_address_argument(cpu);
|
||||
if ((cpu->flags & CPU_FLAG_NEGATIVE) || (cpu->flags & CPU_FLAG_ZERO)) {
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
cpu->pc += CPU_INSTRUCTION_SIZE;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@@ -35,6 +35,7 @@ typedef struct {
|
||||
uint32_t pc; // Program counter
|
||||
uint32_t stack_ptr; // Stack pointer
|
||||
uint8_t flags; // Status flags
|
||||
uint32_t programEnd;
|
||||
uint8_t mode;
|
||||
uint32_t cycle;
|
||||
} CPU;
|
||||
|
Reference in New Issue
Block a user