Add highlighting, fixed len instructions and more
This commit is contained in:
@@ -290,7 +290,7 @@ const char *readLine(const char *source, char *buffer, size_t maxLen) {
|
|||||||
// The address is simply the offset into the output machine code buffer.
|
// The address is simply the offset into the output machine code buffer.
|
||||||
// For this example, every instruction is assumed to have a fixed length (opcode plus operand bytes).
|
// For this example, every instruction is assumed to have a fixed length (opcode plus operand bytes).
|
||||||
//
|
//
|
||||||
int firstPass(const char *source) {
|
void firstPass(const char *source) {
|
||||||
char line[MAX_LINE_LENGTH];
|
char line[MAX_LINE_LENGTH];
|
||||||
int addr = 0;
|
int addr = 0;
|
||||||
labelCount = 0;
|
labelCount = 0;
|
||||||
@@ -316,152 +316,170 @@ int firstPass(const char *source) {
|
|||||||
continue;
|
continue;
|
||||||
strcpy(line, rest);
|
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 = 0; // Instruction size in bytes.
|
// // Parse the mnemonic and operands.
|
||||||
if (baseOpcode == -2) {
|
// char mnemonic[32], operand1[64], operand2[64], operand3[64];
|
||||||
// MOV instruction requires further resolution.
|
// operand1[0] = '\0';
|
||||||
int resolvedOpcode = resolveMOV(operand1, operand2);
|
// operand2[0] = '\0';
|
||||||
if (resolvedOpcode == MOV_RN_IMM || resolvedOpcode == MOV_RN_RM) {
|
// int tokenCount = sscanf(line, "%31s %63[^ ] %63[^ ] %63s",
|
||||||
size = 3; // opcode (1) + reg (1) + immediate or register (1)
|
// mnemonic, operand1, operand2, operand3);
|
||||||
} 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 {
|
// // Use the mapper to get a base opcode.
|
||||||
size = 3; // fallback
|
// int baseOpcode = getOpcode(mnemonic);
|
||||||
}
|
// if (baseOpcode == -1) {
|
||||||
} else if (baseOpcode < 0) {
|
// printf("Unknown instruction: %s\n", mnemonic);
|
||||||
// Ambiguous instructions that use resolveALU.
|
// continue;
|
||||||
// For JMP and jump-bit instructions, the jump target is in operand1.
|
// }
|
||||||
if (baseOpcode == -11) {
|
//
|
||||||
// JMP: if operand1 starts with '+' or '-', it's relative.
|
// int size = CPU_INSTRUCTION_SIZE; // Instruction size in bytes.
|
||||||
if (operand1[0] == '+' || operand1[0] == '-') {
|
// if (baseOpcode == -2) {
|
||||||
// resolve as JMP_REL.
|
// // MOV instruction requires further resolution.
|
||||||
int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
// int resolvedOpcode = resolveMOV(operand1, operand2);
|
||||||
size = 2; // opcode (1) + 1-byte relative offset (1)
|
// if (resolvedOpcode == MOV_RN_IMM || resolvedOpcode == MOV_RN_RM) {
|
||||||
} else {
|
// size = 3; // opcode (1) + reg (1) + immediate or register (1)
|
||||||
int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
// } else if (resolvedOpcode == MOV_RN_ADDR || resolvedOpcode == MOV_ADDR_RN) {
|
||||||
size = 5; // opcode (1) + 32-bit absolute address (4)
|
// size = 6; // opcode (1) + one operand as register (1) and one 32-bit address (4) [+ padding if needed]
|
||||||
}
|
// } else {
|
||||||
} else if (baseOpcode == -14 || baseOpcode == -15) {
|
// size = 3; // fallback
|
||||||
// JMPBS or JMPBC (jump if bit set/clear)
|
// }
|
||||||
int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
// } else if (baseOpcode < 0) {
|
||||||
if (operand1[0] == 'R' || operand1[0] == 'r')
|
// // Ambiguous instructions that use resolveALU.
|
||||||
size = 7; // opcode (1) + register (1) + bit (1) + 32-bit jump address (4)
|
// // For JMP and jump-bit instructions, the jump target is in operand1.
|
||||||
else
|
// if (baseOpcode == -11) {
|
||||||
size = 10; // opcode (1) + 32-bit memory address (4) + bit (1) + 32-bit jump address (4)
|
// // JMP: if operand1 starts with '+' or '-', it's relative.
|
||||||
} else {
|
// if (operand1[0] == '+' || operand1[0] == '-') {
|
||||||
// For arithmetic ALU instructions and INC/DEC,
|
// // resolve as JMP_REL.
|
||||||
// use operand2 to resolve.
|
// int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
||||||
int resolvedOpcode = resolveALU(baseOpcode, operand2);
|
// size = 2; // opcode (1) + 1-byte relative offset (1)
|
||||||
switch (resolvedOpcode) {
|
// } else {
|
||||||
case ADD_RN_RM:
|
// int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
||||||
case SUB_RN_RM:
|
// size = 5; // opcode (1) + 32-bit absolute address (4)
|
||||||
case MUL_RN_RM:
|
// }
|
||||||
case DIV_RN_RM:
|
// } else if (baseOpcode == -14 || baseOpcode == -15) {
|
||||||
case MOD_RN_RM:
|
// // JMPBS or JMPBC (jump if bit set/clear)
|
||||||
case AND_RN_RM:
|
// int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
||||||
case OR_RN_RM:
|
// if (operand1[0] == 'R' || operand1[0] == 'r')
|
||||||
case XOR_RN_RM:
|
// size = 7; // opcode (1) + register (1) + bit (1) + 32-bit jump address (4)
|
||||||
case ADD_RN_IMM:
|
// else
|
||||||
case SUB_RN_IMM:
|
// size = 10; // opcode (1) + 32-bit memory address (4) + bit (1) + 32-bit jump address (4)
|
||||||
case MUL_RN_IMM:
|
// } else {
|
||||||
case DIV_RN_IMM:
|
// // For arithmetic ALU instructions and INC/DEC,
|
||||||
case MOD_RN_IMM:
|
// // use operand2 to resolve.
|
||||||
case AND_RN_IMM:
|
// int resolvedOpcode = resolveALU(baseOpcode, operand2);
|
||||||
case OR_RN_IMM:
|
// switch (resolvedOpcode) {
|
||||||
case XOR_RN_IMM:
|
// case ADD_RN_RM:
|
||||||
size = 3; // opcode (1) + register (1) + reg/immediate (1)
|
// case SUB_RN_RM:
|
||||||
break;
|
// case MUL_RN_RM:
|
||||||
case INC_RN:
|
// case DIV_RN_RM:
|
||||||
case DEC_RN:
|
// case MOD_RN_RM:
|
||||||
size = 2; // opcode (1) + register (1)
|
// case AND_RN_RM:
|
||||||
break;
|
// case OR_RN_RM:
|
||||||
case INC_ADDR:
|
// case XOR_RN_RM:
|
||||||
case DEC_ADDR:
|
// case ADD_RN_IMM:
|
||||||
size = 5; // opcode (1) + 32-bit address (4)
|
// case SUB_RN_IMM:
|
||||||
break;
|
// case MUL_RN_IMM:
|
||||||
default:
|
// case DIV_RN_IMM:
|
||||||
size = 3;
|
// case MOD_RN_IMM:
|
||||||
break;
|
// case AND_RN_IMM:
|
||||||
}
|
// case OR_RN_IMM:
|
||||||
}
|
// case XOR_RN_IMM:
|
||||||
} else {
|
// size = 3; // opcode (1) + register (1) + reg/immediate (1)
|
||||||
// Non-ambiguous instructions that have positive opcodes.
|
// break;
|
||||||
// Use the mapping value (baseOpcode) directly.
|
// case INC_RN:
|
||||||
switch (baseOpcode) {
|
// case DEC_RN:
|
||||||
case NOP:
|
// size = 2; // opcode (1) + register (1)
|
||||||
case BRK:
|
// break;
|
||||||
case HLT:
|
// case INC_ADDR:
|
||||||
size = 1;
|
// case DEC_ADDR:
|
||||||
break;
|
// size = 5; // opcode (1) + 32-bit address (4)
|
||||||
case SWAP:
|
// break;
|
||||||
case CMP:
|
// default:
|
||||||
size = 3;
|
// size = 3;
|
||||||
break;
|
// break;
|
||||||
case SWAPN:
|
// }
|
||||||
case NEG_RN:
|
// }
|
||||||
case NOT_RN:
|
// } else {
|
||||||
size = 2;
|
// // Non-ambiguous instructions that have positive opcodes.
|
||||||
break;
|
// // Use the mapping value (baseOpcode) directly.
|
||||||
case SHL_RN_IMM:
|
// switch (baseOpcode) {
|
||||||
case SHR_RN_IMM:
|
// case NOP:
|
||||||
case SAR_RN_IMM:
|
// case BRK:
|
||||||
size = 3;
|
// case HLT:
|
||||||
break;
|
// size = 1;
|
||||||
case JE:
|
// break;
|
||||||
case JNE:
|
// case SWAP:
|
||||||
case JG:
|
// case CMP:
|
||||||
case JL:
|
// size = 3;
|
||||||
case JGE:
|
// break;
|
||||||
case JLE:
|
// case SWAPN:
|
||||||
case CALL:
|
// case NEG_RN:
|
||||||
size = 5; // opcode (1) + 32-bit address (4)\n break;
|
// case NOT_RN:
|
||||||
case RET:
|
// size = 2;
|
||||||
size = 1;
|
// break;
|
||||||
break;
|
// case SHL_RN_IMM:
|
||||||
default:
|
// case SHR_RN_IMM:
|
||||||
size = 3;
|
// case SAR_RN_IMM:
|
||||||
break;
|
// size = 3;
|
||||||
}
|
// break;
|
||||||
}
|
// case JE:
|
||||||
addr += size;
|
// case JNE:
|
||||||
}
|
// case JG:
|
||||||
return addr;
|
// 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 secondPass(const char *source, uint8_t *code) {
|
int completePass(const char *source, CPU *cpu, bool erase) {
|
||||||
|
if (erase) {
|
||||||
|
memset(cpu->memory, 0, sizeof(cpu->memory));
|
||||||
|
memset(cpu->regs, 0, sizeof(cpu->regs));
|
||||||
|
memset(cpu->stack, 0, sizeof(cpu->stack));
|
||||||
|
memset(cpu->addrToLineMapper, 0, sizeof(cpu->addrToLineMapper));
|
||||||
|
cpu->pc = 0;
|
||||||
|
cpu->stack_ptr = 0;
|
||||||
|
cpu->flags = 0;
|
||||||
|
cpu->cycle = 0;
|
||||||
|
}
|
||||||
|
// First pass: determine label addresses.
|
||||||
|
firstPass(source);
|
||||||
|
|
||||||
char line[MAX_LINE_LENGTH];
|
char line[MAX_LINE_LENGTH];
|
||||||
int addr = 0;
|
uint32_t addr = 0;
|
||||||
const char *ptr = source;
|
const char *ptr = source;
|
||||||
|
|
||||||
|
uint32_t lineIndex = 0;
|
||||||
|
|
||||||
while (*ptr) {
|
while (*ptr) {
|
||||||
ptr = readLine(ptr, line, sizeof(line));
|
ptr = readLine(ptr, line, sizeof(line));
|
||||||
trim(line);
|
trim(line);
|
||||||
if (line[0] == '\0' || line[0] == ';' || line[0] == '#')
|
if (line[0] == '\0' || line[0] == ';' || line[0] == '#') {
|
||||||
|
lineIndex++;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove any label definitions (up to the colon).
|
// Remove any label definitions (up to the colon).
|
||||||
char *colon = strchr(line, ':');
|
char *colon = strchr(line, ':');
|
||||||
if (colon != NULL) {
|
if (colon != NULL) {
|
||||||
*colon = ' '; // Replace the colon so the rest of the line can be parsed.
|
lineIndex++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (strlen(line) == 0)
|
if (strlen(line) == 0)
|
||||||
@@ -470,11 +488,12 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
// 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",
|
int tokenCount = 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.)
|
||||||
|
|
||||||
|
uint32_t oldAddr = addr;
|
||||||
// Map the mnemonic to a base opcode.
|
// Map the mnemonic to a base opcode.
|
||||||
int baseOpcode = getOpcode(mnemonic);
|
int baseOpcode = getOpcode(mnemonic);
|
||||||
if (baseOpcode == -1) {
|
if (baseOpcode == -1) {
|
||||||
@@ -489,17 +508,17 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int resolvedOpcode = resolveMOV(operand1, operand2);
|
int resolvedOpcode = resolveMOV(operand1, operand2);
|
||||||
code[addr++] = resolvedOpcode;
|
cpu->memory[addr++] = resolvedOpcode;
|
||||||
if (resolvedOpcode == MOV_RN_IMM) {
|
if (resolvedOpcode == MOV_RN_IMM) {
|
||||||
int reg = parseRegister(operand1);
|
int reg = parseRegister(operand1);
|
||||||
uint8_t imm = parseImmediate(operand2);
|
uint8_t imm = parseImmediate(operand2);
|
||||||
code[addr++] = reg;
|
cpu->memory[addr++] = reg;
|
||||||
code[addr++] = imm;
|
cpu->memory[addr++] = imm;
|
||||||
} else if (resolvedOpcode == MOV_RN_RM) {
|
} else if (resolvedOpcode == MOV_RN_RM) {
|
||||||
int regDest = parseRegister(operand1);
|
int regDest = parseRegister(operand1);
|
||||||
int regSrc = parseRegister(operand2);
|
int regSrc = parseRegister(operand2);
|
||||||
code[addr++] = regDest;
|
cpu->memory[addr++] = regDest;
|
||||||
code[addr++] = regSrc;
|
cpu->memory[addr++] = regSrc;
|
||||||
} else if (resolvedOpcode == MOV_RN_ADDR) {
|
} else if (resolvedOpcode == MOV_RN_ADDR) {
|
||||||
int reg = parseRegister(operand1);
|
int reg = parseRegister(operand1);
|
||||||
// Assume source is written as "[address]": remove the brackets.
|
// Assume source is written as "[address]": remove the brackets.
|
||||||
@@ -507,11 +526,10 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
strncpy(addrStr, operand2 + 1, strlen(operand2) - 2);
|
strncpy(addrStr, operand2 + 1, strlen(operand2) - 2);
|
||||||
addrStr[strlen(operand2) - 2] = '\0';
|
addrStr[strlen(operand2) - 2] = '\0';
|
||||||
uint32_t memAddr = (uint32_t) strtoul(addrStr, NULL, 0);
|
uint32_t memAddr = (uint32_t) strtoul(addrStr, NULL, 0);
|
||||||
code[addr++] = reg;
|
cpu->memory[addr++] = reg;
|
||||||
code[addr++] = (memAddr >> 24) & 0xFF;
|
cpu->memory[addr++] = memAddr & 0xFF;
|
||||||
code[addr++] = (memAddr >> 16) & 0xFF;
|
cpu->memory[addr++] = (memAddr >> 8) & 0xFF;
|
||||||
code[addr++] = (memAddr >> 8) & 0xFF;
|
cpu->memory[addr++] = (memAddr >> 16) & 0xFF;
|
||||||
code[addr++] = memAddr & 0xFF;
|
|
||||||
} else if (resolvedOpcode == MOV_ADDR_RN) {
|
} else if (resolvedOpcode == MOV_ADDR_RN) {
|
||||||
// Destination is memory (written as "[address]").
|
// Destination is memory (written as "[address]").
|
||||||
char addrStr[32];
|
char addrStr[32];
|
||||||
@@ -519,11 +537,10 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
addrStr[strlen(operand1) - 2] = '\0';
|
addrStr[strlen(operand1) - 2] = '\0';
|
||||||
uint32_t memAddr = (uint32_t) strtoul(addrStr, NULL, 0);
|
uint32_t memAddr = (uint32_t) strtoul(addrStr, NULL, 0);
|
||||||
int reg = parseRegister(operand2);
|
int reg = parseRegister(operand2);
|
||||||
code[addr++] = (memAddr >> 24) & 0xFF;
|
cpu->memory[addr++] = memAddr & 0xFF;
|
||||||
code[addr++] = (memAddr >> 16) & 0xFF;
|
cpu->memory[addr++] = (memAddr >> 8) & 0xFF;
|
||||||
code[addr++] = (memAddr >> 8) & 0xFF;
|
cpu->memory[addr++] = (memAddr >> 16) & 0xFF;
|
||||||
code[addr++] = memAddr & 0xFF;
|
cpu->memory[addr++] = reg;
|
||||||
code[addr++] = reg;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// --- INC and DEC (baseOpcode == -12 or -13) ---
|
// --- INC and DEC (baseOpcode == -12 or -13) ---
|
||||||
@@ -534,20 +551,19 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
||||||
code[addr++] = resolvedOpcode;
|
cpu->memory[addr++] = resolvedOpcode;
|
||||||
if (operand1[0] == 'R' || operand1[0] == 'r') {
|
if (operand1[0] == 'R' || operand1[0] == 'r') {
|
||||||
int reg = parseRegister(operand1);
|
int reg = parseRegister(operand1);
|
||||||
code[addr++] = reg;
|
cpu->memory[addr++] = reg;
|
||||||
} else {
|
} else {
|
||||||
// Assume memory reference written as "[address]".
|
// Assume memory reference written as "[address]".
|
||||||
char addrStr[32];
|
char addrStr[32];
|
||||||
strncpy(addrStr, operand1 + 1, strlen(operand1) - 2);
|
strncpy(addrStr, operand1 + 1, strlen(operand1) - 2);
|
||||||
addrStr[strlen(operand1) - 2] = '\0';
|
addrStr[strlen(operand1) - 2] = '\0';
|
||||||
uint32_t memAddr = (uint32_t) strtoul(addrStr, NULL, 0);
|
uint32_t memAddr = (uint32_t) strtoul(addrStr, NULL, 0);
|
||||||
code[addr++] = (memAddr >> 24) & 0xFF;
|
cpu->memory[addr++] = memAddr & 0xFF;
|
||||||
code[addr++] = (memAddr >> 16) & 0xFF;
|
cpu->memory[addr++] = (memAddr >> 8) & 0xFF;
|
||||||
code[addr++] = (memAddr >> 8) & 0xFF;
|
cpu->memory[addr++] = (memAddr >> 16) & 0xFF;
|
||||||
code[addr++] = memAddr & 0xFF;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// --- Other Ambiguous ALU Instructions (ADD, SUB, MUL, etc.) ---
|
// --- Other Ambiguous ALU Instructions (ADD, SUB, MUL, etc.) ---
|
||||||
@@ -559,15 +575,15 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int resolvedOpcode = resolveALU(baseOpcode, operand2);
|
int resolvedOpcode = resolveALU(baseOpcode, operand2);
|
||||||
code[addr++] = resolvedOpcode;
|
cpu->memory[addr++] = resolvedOpcode;
|
||||||
int regDest = parseRegister(operand1);
|
int regDest = parseRegister(operand1);
|
||||||
code[addr++] = regDest;
|
cpu->memory[addr++] = regDest;
|
||||||
if (operand2[0] == 'R' || operand2[0] == 'r') {
|
if (operand2[0] == 'R' || operand2[0] == 'r') {
|
||||||
int regSrc = parseRegister(operand2);
|
int regSrc = parseRegister(operand2);
|
||||||
code[addr++] = regSrc;
|
cpu->memory[addr++] = regSrc;
|
||||||
} else {
|
} else {
|
||||||
uint8_t imm = parseImmediate(operand2);
|
uint8_t imm = parseImmediate(operand2);
|
||||||
code[addr++] = imm;
|
cpu->memory[addr++] = imm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// --- JMP Instruction (baseOpcode == -11) ---
|
// --- JMP Instruction (baseOpcode == -11) ---
|
||||||
@@ -577,18 +593,17 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
||||||
code[addr++] = resolvedOpcode;
|
cpu->memory[addr++] = resolvedOpcode;
|
||||||
if (operand1[0] == '+' || operand1[0] == '-') {
|
if (operand1[0] == '+' || operand1[0] == '-') {
|
||||||
// Relative jump: one-byte offset.
|
// Relative jump: one-byte offset.
|
||||||
uint8_t offset = parseImmediate(operand1);
|
uint8_t offset = parseImmediate(operand1);
|
||||||
code[addr++] = offset;
|
cpu->memory[addr++] = offset;
|
||||||
} else {
|
} else {
|
||||||
// Absolute jump: use label lookup for 32-bit address.
|
// Absolute jump: use label lookup for 32-bit address.
|
||||||
uint32_t jumpAddr = (uint32_t) lookupLabel(operand1);
|
uint32_t jumpAddr = (uint32_t) lookupLabel(operand1);
|
||||||
code[addr++] = (jumpAddr >> 24) & 0xFF;
|
cpu->memory[addr++] = jumpAddr & 0xFF;
|
||||||
code[addr++] = (jumpAddr >> 16) & 0xFF;
|
cpu->memory[addr++] = (jumpAddr >> 8) & 0xFF;
|
||||||
code[addr++] = (jumpAddr >> 8) & 0xFF;
|
cpu->memory[addr++] = (jumpAddr >> 16) & 0xFF;
|
||||||
code[addr++] = jumpAddr & 0xFF;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// --- Jump Bit Set/Clear Instructions (JMPBS, JMPBC) ---
|
// --- Jump Bit Set/Clear Instructions (JMPBS, JMPBC) ---
|
||||||
@@ -598,33 +613,31 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
||||||
code[addr++] = resolvedOpcode;
|
cpu->memory[addr++] = resolvedOpcode;
|
||||||
// Encode the source operand (register or memory).
|
// Encode the source operand (register or memory).
|
||||||
if (operand1[0] == 'R' || operand1[0] == 'r') {
|
if (operand1[0] == 'R' || operand1[0] == 'r') {
|
||||||
int reg = parseRegister(operand1);
|
int reg = parseRegister(operand1);
|
||||||
code[addr++] = reg;
|
cpu->memory[addr++] = reg;
|
||||||
} else {
|
} else {
|
||||||
char addrStr[32];
|
char addrStr[32];
|
||||||
strncpy(addrStr, operand1 + 1, strlen(operand1) - 2);
|
strncpy(addrStr, operand1 + 1, strlen(operand1) - 2);
|
||||||
addrStr[strlen(operand1) - 2] = '\0';
|
addrStr[strlen(operand1) - 2] = '\0';
|
||||||
uint32_t memAddr = (uint32_t) strtoul(addrStr, NULL, 0);
|
uint32_t memAddr = (uint32_t) strtoul(addrStr, NULL, 0);
|
||||||
code[addr++] = (memAddr >> 24) & 0xFF;
|
cpu->memory[addr++] = memAddr & 0xFF;
|
||||||
code[addr++] = (memAddr >> 16) & 0xFF;
|
cpu->memory[addr++] = (memAddr >> 8) & 0xFF;
|
||||||
code[addr++] = (memAddr >> 8) & 0xFF;
|
cpu->memory[addr++] = (memAddr >> 16) & 0xFF;
|
||||||
code[addr++] = memAddr & 0xFF;
|
|
||||||
}
|
}
|
||||||
// Encode the bit number (a one-byte immediate).
|
// Encode the bit number (a one-byte immediate).
|
||||||
uint8_t bitVal = parseImmediate(operand2);
|
uint8_t bitVal = parseImmediate(operand2);
|
||||||
code[addr++] = bitVal;
|
cpu->memory[addr++] = bitVal;
|
||||||
// Encode the jump target (label -> 32-bit address).
|
// Encode the jump target (label -> 32-bit address).
|
||||||
uint32_t jumpAddr = (uint32_t) lookupLabel(operand3);
|
uint32_t jumpAddr = (uint32_t) lookupLabel(operand3);
|
||||||
code[addr++] = (jumpAddr >> 24) & 0xFF;
|
cpu->memory[addr++] = jumpAddr & 0xFF;
|
||||||
code[addr++] = (jumpAddr >> 16) & 0xFF;
|
cpu->memory[addr++] = (jumpAddr >> 8) & 0xFF;
|
||||||
code[addr++] = (jumpAddr >> 8) & 0xFF;
|
cpu->memory[addr++] = (jumpAddr >> 16) & 0xFF;
|
||||||
code[addr++] = jumpAddr & 0xFF;
|
|
||||||
}
|
}
|
||||||
// --- Non-ambiguous Instructions ---
|
// --- Non-ambiguous Instructions ---
|
||||||
else if (baseOpcode > 0) {
|
else if (baseOpcode >= 0) {
|
||||||
switch (baseOpcode) {
|
switch (baseOpcode) {
|
||||||
case CMP:
|
case CMP:
|
||||||
case SWAP: {
|
case SWAP: {
|
||||||
@@ -632,11 +645,11 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
fprintf(stderr, "Error: %s requires two operands.\n", mnemonic);
|
fprintf(stderr, "Error: %s requires two operands.\n", mnemonic);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
code[addr++] = baseOpcode;
|
cpu->memory[addr++] = baseOpcode;
|
||||||
int r1 = parseRegister(operand1);
|
int r1 = parseRegister(operand1);
|
||||||
int r2 = parseRegister(operand2);
|
int r2 = parseRegister(operand2);
|
||||||
code[addr++] = r1;
|
cpu->memory[addr++] = r1;
|
||||||
code[addr++] = r2;
|
cpu->memory[addr++] = r2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SWAPN:
|
case SWAPN:
|
||||||
@@ -646,9 +659,9 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
fprintf(stderr, "Error: %s requires one operand.\n", mnemonic);
|
fprintf(stderr, "Error: %s requires one operand.\n", mnemonic);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
code[addr++] = baseOpcode;
|
cpu->memory[addr++] = baseOpcode;
|
||||||
int reg = parseRegister(operand1);
|
int reg = parseRegister(operand1);
|
||||||
code[addr++] = reg;
|
cpu->memory[addr++] = reg;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SHL_RN_IMM:
|
case SHL_RN_IMM:
|
||||||
@@ -658,11 +671,11 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
fprintf(stderr, "Error: %s requires two operands.\n", mnemonic);
|
fprintf(stderr, "Error: %s requires two operands.\n", mnemonic);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
code[addr++] = baseOpcode;
|
cpu->memory[addr++] = baseOpcode;
|
||||||
int reg = parseRegister(operand1);
|
int reg = parseRegister(operand1);
|
||||||
code[addr++] = reg;
|
cpu->memory[addr++] = reg;
|
||||||
uint8_t imm = parseImmediate(operand2);
|
uint8_t imm = parseImmediate(operand2);
|
||||||
code[addr++] = imm;
|
cpu->memory[addr++] = imm;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case JE:
|
case JE:
|
||||||
@@ -676,7 +689,7 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
fprintf(stderr, "Error: %s requires one operand.\n", mnemonic);
|
fprintf(stderr, "Error: %s requires one operand.\n", mnemonic);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
code[addr++] = baseOpcode;
|
cpu->memory[addr++] = baseOpcode;
|
||||||
// If the operand isn’t purely numeric, treat it as a label.
|
// If the operand isn’t purely numeric, treat it as a label.
|
||||||
if (!isdigit(operand1[0])) {
|
if (!isdigit(operand1[0])) {
|
||||||
int labelAddr = lookupLabel(operand1);
|
int labelAddr = lookupLabel(operand1);
|
||||||
@@ -684,16 +697,14 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
fprintf(stderr, "Error: undefined label '%s'\n", operand1);
|
fprintf(stderr, "Error: undefined label '%s'\n", operand1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
code[addr++] = (labelAddr >> 24) & 0xFF;
|
cpu->memory[addr++] = labelAddr & 0xFF;
|
||||||
code[addr++] = (labelAddr >> 16) & 0xFF;
|
cpu->memory[addr++] = (labelAddr >> 8) & 0xFF;
|
||||||
code[addr++] = (labelAddr >> 8) & 0xFF;
|
cpu->memory[addr++] = (labelAddr >> 16) & 0xFF;
|
||||||
code[addr++] = labelAddr & 0xFF;
|
|
||||||
} else {
|
} else {
|
||||||
uint32_t immAddr = (uint32_t) strtoul(operand1, NULL, 0);
|
uint32_t immAddr = (uint32_t) strtoul(operand1, NULL, 0);
|
||||||
code[addr++] = (immAddr >> 24) & 0xFF;
|
cpu->memory[addr++] = immAddr & 0xFF;
|
||||||
code[addr++] = (immAddr >> 16) & 0xFF;
|
cpu->memory[addr++] = (immAddr >> 8) & 0xFF;
|
||||||
code[addr++] = (immAddr >> 8) & 0xFF;
|
cpu->memory[addr++] = (immAddr >> 16) & 0xFF;
|
||||||
code[addr++] = immAddr & 0xFF;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -701,7 +712,7 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
case BRK:
|
case BRK:
|
||||||
case HLT:
|
case HLT:
|
||||||
case NOP: {
|
case NOP: {
|
||||||
code[addr++] = baseOpcode;
|
cpu->memory[addr++] = baseOpcode;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@@ -713,17 +724,14 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
fprintf(stderr, "Error: Unknown instruction '%s'\n", mnemonic);
|
fprintf(stderr, "Error: Unknown instruction '%s'\n", mnemonic);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
const uint32_t remainingBytes = CPU_INSTRUCTION_SIZE - (addr - oldAddr);
|
||||||
|
if (remainingBytes > CPU_INSTRUCTION_SIZE) {
|
||||||
|
printf("HELP, INSTRUCTION SIZE SMALLER THAN INSTRUCTION");
|
||||||
|
}
|
||||||
|
cpu->addrToLineMapper[(addr - (addr % CPU_INSTRUCTION_SIZE)) / CPU_INSTRUCTION_SIZE] = lineIndex;
|
||||||
|
addr += remainingBytes;
|
||||||
|
lineIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void completePass(const char *input, CPU *cpu, bool erase) {
|
|
||||||
// First pass: determine label addresses.
|
|
||||||
if (erase) {
|
|
||||||
init_cpu(cpu);
|
|
||||||
}
|
|
||||||
firstPass(input);
|
|
||||||
secondPass(input, cpu->memory);
|
|
||||||
}
|
|
@@ -77,15 +77,13 @@ int resolveALU(int baseOpcode, const char *src);
|
|||||||
// The address is simply the offset into the output machine code buffer.
|
// The address is simply the offset into the output machine code buffer.
|
||||||
// For this example, every instruction is assumed to have a fixed length (opcode plus operand bytes).
|
// For this example, every instruction is assumed to have a fixed length (opcode plus operand bytes).
|
||||||
//
|
//
|
||||||
int firstPass(const char *source);
|
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 secondPass(const char *source, uint8_t *code);
|
int completePass(const char *input, CPU *cpu, bool erase);
|
||||||
|
|
||||||
void completePass(const char *input, CPU *cpu, bool erase);
|
|
||||||
|
|
||||||
|
|
||||||
#endif //RISCB_ASSEMBLER_H
|
#endif //RISCB_ASSEMBLER_H
|
||||||
|
22
cpu/core.c
22
cpu/core.c
@@ -34,11 +34,22 @@ void step(CPU *cpu) {
|
|||||||
cpu->mode |= CPU_MODE_HALTED;
|
cpu->mode |= CPU_MODE_HALTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint8_t opcode = read_mem(cpu, cpu->pc++);
|
|
||||||
uint8_t reg1, reg2, imm, temp, temp2;
|
uint8_t reg1, reg2, imm, temp, temp2;
|
||||||
uint32_t newPC, addrTemp;
|
uint32_t newPC, addrTemp, oldPC;
|
||||||
int32_t cmpResult;
|
int32_t cmpResult;
|
||||||
|
|
||||||
|
oldPC = cpu->pc;
|
||||||
|
newPC = oldPC;
|
||||||
|
|
||||||
|
uint8_t opcode = read_mem(cpu, cpu->pc++);
|
||||||
|
|
||||||
|
|
||||||
|
const uint32_t differenceAlignment = oldPC % CPU_INSTRUCTION_SIZE;
|
||||||
|
|
||||||
|
if (differenceAlignment) {
|
||||||
|
cpu->pc += differenceAlignment;
|
||||||
|
}
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case NOP:
|
case NOP:
|
||||||
//Don't do anything
|
//Don't do anything
|
||||||
@@ -491,5 +502,12 @@ void step(CPU *cpu) {
|
|||||||
printf("Unknown opcode: %d\n", opcode);
|
printf("Unknown opcode: %d\n", opcode);
|
||||||
cpu->mode |= CPU_MODE_ERROR;
|
cpu->mode |= CPU_MODE_ERROR;
|
||||||
}
|
}
|
||||||
|
if (oldPC == newPC) {
|
||||||
|
const uint32_t remainingBytes = CPU_INSTRUCTION_SIZE - (cpu->pc - oldPC);
|
||||||
|
if (remainingBytes > CPU_INSTRUCTION_SIZE) {
|
||||||
|
printf("HELP, INSTRUCTION SIZE SMALLER THAN INSTRUCTION");
|
||||||
|
}
|
||||||
|
cpu->pc += remainingBytes;
|
||||||
|
}
|
||||||
cpu->cycle++;
|
cpu->cycle++;
|
||||||
}
|
}
|
@@ -23,13 +23,16 @@
|
|||||||
#define CPU_MODE_STEP (1 << 4)
|
#define CPU_MODE_STEP (1 << 4)
|
||||||
#define CPU_MODE_SECOND (1 << 5)
|
#define CPU_MODE_SECOND (1 << 5)
|
||||||
|
|
||||||
|
#define CPU_INSTRUCTION_SIZE 8 //Biggest instruction
|
||||||
|
|
||||||
|
|
||||||
// CPU state
|
// CPU state
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t regs[REG_COUNT];
|
uint8_t regs[REG_COUNT];
|
||||||
uint8_t memory[MEM_SIZE];
|
uint8_t memory[MEM_SIZE];
|
||||||
uint32_t pc; // Program counter
|
|
||||||
uint32_t stack[STACK_SIZE]; // Stack pointer
|
uint32_t stack[STACK_SIZE]; // Stack pointer
|
||||||
|
uint32_t addrToLineMapper[MEM_SIZE / CPU_INSTRUCTION_SIZE];
|
||||||
|
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
|
||||||
uint8_t mode;
|
uint8_t mode;
|
||||||
|
12
cpu/memory.c
12
cpu/memory.c
@@ -37,9 +37,13 @@ uint32_t read_mem32(CPU *cpu, uint32_t addr) {
|
|||||||
return read_mem16(cpu, addr) | (read_mem16(cpu, addr + 2) << 16);
|
return read_mem16(cpu, addr) | (read_mem16(cpu, addr + 2) << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t read_mem24(CPU *cpu, uint32_t addr) {
|
||||||
|
return read_mem16(cpu, addr) | (read_mem(cpu, addr + 2) << 16);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t read_address_argument(CPU *cpu) {
|
uint32_t read_address_argument(CPU *cpu) {
|
||||||
uint32_t out = read_mem32(cpu, cpu->pc);
|
uint32_t out = read_mem24(cpu, cpu->pc);
|
||||||
cpu->pc += 4;
|
cpu->pc += 3;
|
||||||
if (out >= MEM_SIZE) {
|
if (out >= MEM_SIZE) {
|
||||||
out = MEM_SIZE - 1;
|
out = MEM_SIZE - 1;
|
||||||
}
|
}
|
||||||
@@ -58,8 +62,7 @@ void write_stack(CPU *cpu) {
|
|||||||
for (uint32_t reg = 0; reg < REG_COUNT; reg += 4) {
|
for (uint32_t reg = 0; reg < REG_COUNT; reg += 4) {
|
||||||
uint32_t packed = cpu->regs[reg] |
|
uint32_t packed = cpu->regs[reg] |
|
||||||
((reg + 1 < REG_COUNT) ? (cpu->regs[reg + 1] << 8) : 0) |
|
((reg + 1 < REG_COUNT) ? (cpu->regs[reg + 1] << 8) : 0) |
|
||||||
((reg + 2 < REG_COUNT) ? (cpu->regs[reg + 2] << 16) : 0) |
|
((reg + 2 < REG_COUNT) ? (cpu->regs[reg + 2] << 16) : 0);
|
||||||
((reg + 3 < REG_COUNT) ? (cpu->regs[reg + 3] << 24) : 0);
|
|
||||||
cpu->stack[++cpu->stack_ptr] = packed;
|
cpu->stack[++cpu->stack_ptr] = packed;
|
||||||
}
|
}
|
||||||
cpu->stack[++cpu->stack_ptr] = cpu->flags;
|
cpu->stack[++cpu->stack_ptr] = cpu->flags;
|
||||||
@@ -83,7 +86,6 @@ void read_stack(CPU *cpu) {
|
|||||||
cpu->regs[reg] = (packed & 0xFF);
|
cpu->regs[reg] = (packed & 0xFF);
|
||||||
if (reg - 1 >= 0) cpu->regs[reg - 1] = ((packed >> 8) & 0xFF);
|
if (reg - 1 >= 0) cpu->regs[reg - 1] = ((packed >> 8) & 0xFF);
|
||||||
if (reg - 2 >= 0) cpu->regs[reg - 2] = ((packed >> 16) & 0xFF);
|
if (reg - 2 >= 0) cpu->regs[reg - 2] = ((packed >> 16) & 0xFF);
|
||||||
if (reg - 3 >= 0) cpu->regs[reg - 3] = ((packed >> 24) & 0xFF);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore PC
|
// Restore PC
|
||||||
|
53
docs/examples/fulltest.bsm
Normal file
53
docs/examples/fulltest.bsm
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
; Test Program using all opcodes
|
||||||
|
|
||||||
|
START:
|
||||||
|
NOP ; No operation (does nothing, advances to the next instruction)
|
||||||
|
MOV R1, 0x10 ; Move immediate value 0x10 to register R1
|
||||||
|
MOV R2, R1 ; Move value from R1 to R2
|
||||||
|
MOV [0x2000], R3 ; Load value from memory address 0x2000 into R3
|
||||||
|
MOV R1, [0x2000] ; Store R1 value to memory address 0x2000
|
||||||
|
SWAP R1, R2 ; Swap values between R1 and R2
|
||||||
|
SWAPN R1 ; Swap nibbles within R1
|
||||||
|
ADD R1, R2 ; Add R2 to R1
|
||||||
|
ADD R1, 0x10 ; Add immediate 0x10 to R1
|
||||||
|
SUB R1, R2 ; Subtract R2 from R1
|
||||||
|
SUB R1, 0x10 ; Subtract immediate 0x10 from R1
|
||||||
|
MUL R1, R2 ; Multiply R1 by R2
|
||||||
|
MUL R1, 0x10 ; Multiply R1 by immediate 0x10
|
||||||
|
DIV R1, R2 ; Divide R1 by R2
|
||||||
|
DIV R1, 0x10 ; Divide R1 by immediate 0x10
|
||||||
|
MOD R1, R2 ; Compute remainder of R1 / R2
|
||||||
|
MOD R1, 0x10 ; Compute remainder of R1 / 0x10
|
||||||
|
NEG R1 ; Negate R1
|
||||||
|
AND R1, R2 ; Bitwise AND of R1 and R2
|
||||||
|
AND R1, 0x10 ; Bitwise AND R1 with immediate 0x10
|
||||||
|
OR R1, R2 ; Bitwise OR of R1 and R2
|
||||||
|
OR R1, 0x10 ; Bitwise OR R1 with immediate 0x10
|
||||||
|
XOR R1, R2 ; Bitwise XOR of R1 and R2
|
||||||
|
XOR R1, 0x10 ; Bitwise XOR R1 with immediate 0x10
|
||||||
|
NOT R1 ; Bitwise NOT of R1
|
||||||
|
SHL R1, 2 ; Logical shift left R1 by 2 bits
|
||||||
|
SHR R1, 2 ; Logical shift right R1 by 2 bits
|
||||||
|
SAR R1, 2 ; Arithmetic shift right R1 by 2 bits (sign extended)
|
||||||
|
JMP 0x3000 ; Jump to address 0x3000
|
||||||
|
JMP +5 ; Jump 5 bytes forward
|
||||||
|
INC R1 ; Increment R1
|
||||||
|
INC [0x2000] ; Increment value at memory address 0x2000
|
||||||
|
DEC R1 ; Decrement R1
|
||||||
|
DEC [0x2000] ; Decrement value at memory address 0x2000
|
||||||
|
CMP R1, R2 ; Compare R1 and R2 (sets flags based on R1 - R2)
|
||||||
|
JE 0x4000 ; Jump to 0x4000 if equal (zero flag set)
|
||||||
|
JNE 0x4000 ; Jump to 0x4000 if not equal (zero flag not set)
|
||||||
|
JG 0x4000 ; Jump to 0x4000 if greater
|
||||||
|
JL 0x4000 ; Jump to 0x4000 if less
|
||||||
|
JGE 0x4000 ; Jump to 0x4000 if greater or equal
|
||||||
|
JLE 0x4000 ; Jump to 0x4000 if less or equal
|
||||||
|
CALL 0x5000 ; Call subroutine at 0x5000
|
||||||
|
RET ; Return from subroutine
|
||||||
|
JMPBC R1, 3, 0x4000 ; Jump to address 0x4000 if bit 3 in register R1 is not set
|
||||||
|
JMPBC 0x2000, 5, 0x5000 ; Jump to address 0x5000 if bit 5 in memory at address 0x2000 is not set
|
||||||
|
JMPBS R2, 1, 0x6000 ; Jump to address 0x6000 if bit 1 in register R2 is set
|
||||||
|
JMPBS 0x3000, 7, 0x7000 ; Jump to address 0x7000 if bit 7 in memory at address 0x3000 is set
|
||||||
|
|
||||||
|
; Halt the program
|
||||||
|
HLT
|
6
docs/examples/jmptest.bsm
Normal file
6
docs/examples/jmptest.bsm
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
TEST:
|
||||||
|
INC R1
|
||||||
|
INC R2
|
||||||
|
MOV R2 [20]
|
||||||
|
JMP TEST
|
||||||
|
HLT
|
4
docs/examples/test1.bsm
Normal file
4
docs/examples/test1.bsm
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
INC R1
|
||||||
|
BRK
|
||||||
|
INC R2
|
||||||
|
HLT
|
195
docs/instructions.md
Normal file
195
docs/instructions.md
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
### **NOP**
|
||||||
|
|
||||||
|
`NOP` - No operation (does nothing, advances to the next instruction)
|
||||||
|
|
||||||
|
### **BRK**
|
||||||
|
|
||||||
|
`BRK` - Pause CPU (halts execution until resumed)
|
||||||
|
|
||||||
|
### **HLT**
|
||||||
|
|
||||||
|
`HLT` - Halt CPU execution
|
||||||
|
|
||||||
|
### **MOV_RN_IMM**
|
||||||
|
|
||||||
|
`MOV R1, 0x10` - Move immediate value `0x10` to register `R1`
|
||||||
|
|
||||||
|
### **MOV_RN_RM**
|
||||||
|
|
||||||
|
`MOV R2, R1` - Move value from `R1` to `R2`
|
||||||
|
|
||||||
|
### **MOV_RN_ADDR**
|
||||||
|
|
||||||
|
`MOV R3, [0x2000]` - Load value from memory address `0x2000` into `R3`
|
||||||
|
|
||||||
|
### **MOV_ADDR_RN**
|
||||||
|
|
||||||
|
`MOV [0x2000], R1` - Store `R1` value to memory address `0x2000`
|
||||||
|
|
||||||
|
### **SWAP**
|
||||||
|
|
||||||
|
`SWAP R1, R2` - Swap values between `R1` and `R2`
|
||||||
|
|
||||||
|
### **SWAPN**
|
||||||
|
|
||||||
|
`SWAPN R1` - Swap nibbles within `R1`
|
||||||
|
|
||||||
|
### **ADD_RN_RM**
|
||||||
|
|
||||||
|
`ADD R1, R2` - Add `R2` to `R1` (`R1 = R1 + R2`)
|
||||||
|
|
||||||
|
### **ADD_RN_IMM**
|
||||||
|
|
||||||
|
`ADD R1, 0x10` - Add immediate `0x10` to `R1` (`R1 = R1 + 0x10`)
|
||||||
|
|
||||||
|
### **SUB_RN_RM**
|
||||||
|
|
||||||
|
`SUB R1, R2` - Subtract `R2` from `R1` (`R1 = R1 - R2`)
|
||||||
|
|
||||||
|
### **SUB_RN_IMM**
|
||||||
|
|
||||||
|
`SUB R1, 0x10` - Subtract immediate `0x10` from `R1` (`R1 = R1 - 0x10`)
|
||||||
|
|
||||||
|
### **MUL_RN_RM**
|
||||||
|
|
||||||
|
`MUL R1, R2` - Multiply `R1` by `R2` (`R1 = R1 * R2`)
|
||||||
|
|
||||||
|
### **MUL_RN_IMM**
|
||||||
|
|
||||||
|
`MUL R1, 0x10` - Multiply `R1` by immediate `0x10` (`R1 = R1 * 0x10`)
|
||||||
|
|
||||||
|
### **DIV_RN_RM**
|
||||||
|
|
||||||
|
`DIV R1, R2` - Divide `R1` by `R2` (`R1 = R1 / R2`)
|
||||||
|
|
||||||
|
### **DIV_RN_IMM**
|
||||||
|
|
||||||
|
`DIV R1, 0x10` - Divide `R1` by immediate `0x10` (`R1 = R1 / 0x10`)
|
||||||
|
|
||||||
|
### **MOD_RN_RM**
|
||||||
|
|
||||||
|
`MOD R1, R2` - Compute remainder of `R1 / R2` (`R1 = R1 % R2`)
|
||||||
|
|
||||||
|
### **MOD_RN_IMM**
|
||||||
|
|
||||||
|
`MOD R1, 0x10` - Compute remainder of `R1 / 0x10` (`R1 = R1 % 0x10`)
|
||||||
|
|
||||||
|
### **NEG_RN**
|
||||||
|
|
||||||
|
`NEG R1` - Negate `R1` (`R1 = -R1`)
|
||||||
|
|
||||||
|
### **AND_RN_RM**
|
||||||
|
|
||||||
|
`AND R1, R2` - Bitwise AND of `R1` and `R2` (`R1 = R1 & R2`)
|
||||||
|
|
||||||
|
### **AND_RN_IMM**
|
||||||
|
|
||||||
|
`AND R1, 0x10` - Bitwise AND `R1` with immediate `0x10` (`R1 = R1 & 0x10`)
|
||||||
|
|
||||||
|
### **OR_RN_RM**
|
||||||
|
|
||||||
|
`OR R1, R2` - Bitwise OR of `R1` and `R2` (`R1 = R1 | R2`)
|
||||||
|
|
||||||
|
### **OR_RN_IMM**
|
||||||
|
|
||||||
|
`OR R1, 0x10` - Bitwise OR `R1` with immediate `0x10` (`R1 = R1 | 0x10`)
|
||||||
|
|
||||||
|
### **XOR_RN_RM**
|
||||||
|
|
||||||
|
`XOR R1, R2` - Bitwise XOR of `R1` and `R2` (`R1 = R1 ^ R2`)
|
||||||
|
|
||||||
|
### **XOR_RN_IMM**
|
||||||
|
|
||||||
|
`XOR R1, 0x10` - Bitwise XOR `R1` with immediate `0x10` (`R1 = R1 ^ 0x10`)
|
||||||
|
|
||||||
|
### **NOT_RN**
|
||||||
|
|
||||||
|
`NOT R1` - Bitwise NOT of `R1` (`R1 = ~R1`)
|
||||||
|
|
||||||
|
### **SHL_RN_IMM**
|
||||||
|
|
||||||
|
`SHL R1, 2` - Logical shift left `R1` by `2` bits
|
||||||
|
|
||||||
|
### **SHR_RN_IMM**
|
||||||
|
|
||||||
|
`SHR R1, 2` - Logical shift right `R1` by `2` bits
|
||||||
|
|
||||||
|
### **SAR_RN_IMM**
|
||||||
|
|
||||||
|
`SAR R1, 2` - Arithmetic shift right `R1` by `2` bits (sign extended)
|
||||||
|
|
||||||
|
### **JMP**
|
||||||
|
|
||||||
|
`JMP 0x3000` - Jump to address `0x3000`
|
||||||
|
|
||||||
|
### **JMP_REL**
|
||||||
|
|
||||||
|
`JMP +5` - Jump `5` bytes forward
|
||||||
|
|
||||||
|
### **INC_RN**
|
||||||
|
|
||||||
|
`INC R1` - Increment `R1`
|
||||||
|
|
||||||
|
### **INC_ADDR**
|
||||||
|
|
||||||
|
`INC [0x2000]` - Increment value at memory address `0x2000`
|
||||||
|
|
||||||
|
### **DEC_RN**
|
||||||
|
|
||||||
|
`DEC R1` - Decrement `R1`
|
||||||
|
|
||||||
|
### **DEC_ADDR**
|
||||||
|
|
||||||
|
`DEC [0x2000]` - Decrement value at memory address `0x2000`
|
||||||
|
|
||||||
|
### **CMP**
|
||||||
|
|
||||||
|
`CMP R1, R2` - Compare `R1` and `R2` (sets flags based on `R1 - R2`)
|
||||||
|
|
||||||
|
### **JE**
|
||||||
|
|
||||||
|
`JE 0x4000` - Jump to `0x4000` if equal (zero flag set)
|
||||||
|
|
||||||
|
### **JNE**
|
||||||
|
|
||||||
|
`JNE 0x4000` - Jump to `0x4000` if not equal (zero flag not set)
|
||||||
|
|
||||||
|
### **JG**
|
||||||
|
|
||||||
|
`JG 0x4000` - Jump to `0x4000` if greater
|
||||||
|
|
||||||
|
### **JL**
|
||||||
|
|
||||||
|
`JL 0x4000` - Jump to `0x4000` if less
|
||||||
|
|
||||||
|
### **JGE**
|
||||||
|
|
||||||
|
`JGE 0x4000` - Jump to `0x4000` if greater or equal
|
||||||
|
|
||||||
|
### **JLE**
|
||||||
|
|
||||||
|
`JLE 0x4000` - Jump to `0x4000` if less or equal
|
||||||
|
|
||||||
|
### **CALL**
|
||||||
|
|
||||||
|
`CALL 0x5000` - Call subroutine at `0x5000`
|
||||||
|
|
||||||
|
### **RET**
|
||||||
|
|
||||||
|
`RET` - Return from subroutine
|
||||||
|
|
||||||
|
### **JMP_BIT_CLEAR_RN**
|
||||||
|
|
||||||
|
`JMPBC R1, 3, 0x4000` - Jump to address `0x4000` if bit `3` in register `R1` is **not set**.
|
||||||
|
|
||||||
|
### **JMP_BIT_CLEAR_ADDR**
|
||||||
|
|
||||||
|
`JMPBC 0x2000, 5, 0x5000` - Jump to address `0x5000` if bit `5` in memory at address `0x2000` is **not set**.
|
||||||
|
|
||||||
|
### **JMP_BIT_SET_RN**
|
||||||
|
|
||||||
|
`JMPBS R2, 1, 0x6000` - Jump to address `0x6000` if bit `1` in register `R2` **is set**.
|
||||||
|
|
||||||
|
### **JMP_BIT_SET_ADDR**
|
||||||
|
|
||||||
|
`JMPBS 0x3000, 7, 0x7000` - Jump to address `0x7000` if bit `7` in memory at address `0x3000` **is set**.
|
87
main.c
87
main.c
@@ -72,24 +72,26 @@ char *read_file_as_string(const char *filename) {
|
|||||||
return buffer; // Caller must free the memory
|
return buffer; // Caller must free the memory
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateState() {
|
void updateState(bool full) {
|
||||||
cpuStatsTexture = renderVals(&cpu, &smallFont, &smallerFont, renderer);
|
renderVals(&cpu, &smallFont, &smallerFont, renderer, &cpuStatsTexture);
|
||||||
cpuStateTexture = renderState(&cpu, &biggerFont, renderer);
|
renderState(&cpu, &biggerFont, renderer, &cpuStateTexture);
|
||||||
char *dump = hexdump_to_string(cpu.memory, sizeof(cpu.memory));
|
char *dump = hexdump_to_string(cpu.memory, full ? 0 : memoryViewer.cursor_line_offset * 16,
|
||||||
fill_editor_from_string(&memoryViewer, dump, renderer);
|
full ? MEM_SIZE : (memoryViewer.cursor_line_offset * 16) +
|
||||||
|
(memoryViewer.displayLineCount * 16));
|
||||||
|
fill_editor_from_string(&memoryViewer, dump, full ? 0 : memoryViewer.cursor_line_offset, full, renderer);
|
||||||
free(dump);
|
free(dump);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compile(bool erase) {
|
void compile(bool erase) {
|
||||||
generate_string(&codeEditor);
|
generate_string(&codeEditor);
|
||||||
completePass(codeEditor.outputString, &cpu, erase);
|
completePass(codeEditor.outputString, &cpu, erase);
|
||||||
updateState();
|
updateState(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int init() {
|
int init() {
|
||||||
//Initialize SDL
|
//Initialize SDL
|
||||||
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||||
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
|
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -108,17 +110,21 @@ int init() {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
//Get window surface
|
//Get window surface
|
||||||
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
|
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
||||||
if (renderer == NULL) {
|
if (renderer == NULL) {
|
||||||
printf("Renderer could not be created SDL_Error: %s\n", SDL_GetError());
|
printf("Renderer could not be created SDL_Error: %s\n", SDL_GetError());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_Rect viewport = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
|
||||||
|
SDL_RenderSetViewport(renderer, &viewport);
|
||||||
|
|
||||||
|
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||||
biggerFont = prepText(renderer, 16, "../PublicPixel.ttf", 255, 255, 255, 255);
|
biggerFont = prepText(renderer, 16, "../PublicPixel.ttf", 255, 255, 255, 255);
|
||||||
smallFont = prepText(renderer, 12, "../PublicPixel.ttf", 255, 255, 255, 255);
|
smallFont = prepText(renderer, 12, "../PublicPixel.ttf", 255, 255, 255, 255);
|
||||||
smallerFont = prepText(renderer, 8, "../PublicPixel.ttf", 255, 255, 255, 255);
|
smallerFont = prepText(renderer, 8, "../PublicPixel.ttf", 255, 255, 255, 255);
|
||||||
init_editor(&codeEditor, &smallFont, 10, 80, renderer, 34, 1000, 48, false);
|
init_editor(&codeEditor, &smallFont, 10, 80, renderer, 54, 1000, 48, false);
|
||||||
init_editor(&memoryViewer, &smallerFont, 550, 80, renderer, 80, MEM_SIZE / 16 + 2, 70, true);
|
init_editor(&memoryViewer, &smallerFont, 738, 80, renderer, 59, MEM_SIZE / 16 + 2, 70, true);
|
||||||
SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT);
|
SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, NULL);
|
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, NULL);
|
||||||
for (int i = 0; i < editorCount; i++) {
|
for (int i = 0; i < editorCount; i++) {
|
||||||
@@ -135,7 +141,7 @@ int render() {
|
|||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
for (int i = 0; i < editorCount; i++) {
|
for (int i = 0; i < editorCount; i++) {
|
||||||
editor_render(&editors[i], renderer, activeEditorIndex == i, cursor);
|
editor_render(&editors[i], renderer, &cpu, i, activeEditorIndex == i, cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Rect rect2;
|
SDL_Rect rect2;
|
||||||
@@ -146,7 +152,6 @@ int render() {
|
|||||||
|
|
||||||
SDL_QueryTexture(cpuStatsTexture, NULL, NULL, &rect2.w, &rect2.h);
|
SDL_QueryTexture(cpuStatsTexture, NULL, NULL, &rect2.w, &rect2.h);
|
||||||
|
|
||||||
|
|
||||||
SDL_RenderCopy(renderer, cpuStatsTexture, NULL, &rect2);
|
SDL_RenderCopy(renderer, cpuStatsTexture, NULL, &rect2);
|
||||||
|
|
||||||
rect2.x = 100;
|
rect2.x = 100;
|
||||||
@@ -156,7 +161,6 @@ int render() {
|
|||||||
|
|
||||||
SDL_QueryTexture(cpuStateTexture, NULL, NULL, &rect2.w, &rect2.h);
|
SDL_QueryTexture(cpuStateTexture, NULL, NULL, &rect2.w, &rect2.h);
|
||||||
|
|
||||||
|
|
||||||
SDL_RenderCopy(renderer, cpuStateTexture, NULL, &rect2);
|
SDL_RenderCopy(renderer, cpuStateTexture, NULL, &rect2);
|
||||||
|
|
||||||
SDL_RenderPresent(renderer);
|
SDL_RenderPresent(renderer);
|
||||||
@@ -292,43 +296,54 @@ int processEvent(SDL_Event e) {
|
|||||||
int keySym = ConvertKPToNonKP(e.key.keysym.sym);
|
int keySym = ConvertKPToNonKP(e.key.keysym.sym);
|
||||||
int keyMod = e.key.keysym.mod;
|
int keyMod = e.key.keysym.mod;
|
||||||
cursor = true;
|
cursor = true;
|
||||||
|
bool moved = false;
|
||||||
switch (keySym) {
|
switch (keySym) {
|
||||||
case SDLK_UP:
|
case SDLK_UP:
|
||||||
move_cursor_relative(&activeEditor, -1, 0, false, renderer);
|
move_cursor_relative(&activeEditor, -1, 0, false, renderer);
|
||||||
|
moved = true;
|
||||||
break;
|
break;
|
||||||
case SDLK_PAGEUP:
|
case SDLK_PAGEUP:
|
||||||
move_cursor_relative(&activeEditor, -activeEditor.max_lines_display, -1, true, renderer);
|
move_cursor_relative(&activeEditor, -activeEditor.displayLineCount, -1, true, renderer);
|
||||||
|
moved = true;
|
||||||
break;
|
break;
|
||||||
case SDLK_DOWN:
|
case SDLK_DOWN:
|
||||||
move_cursor_relative(&activeEditor, 1, 0, false, renderer);
|
move_cursor_relative(&activeEditor, 1, 0, false, renderer);
|
||||||
|
moved = true;
|
||||||
break;
|
break;
|
||||||
case SDLK_PAGEDOWN:
|
case SDLK_PAGEDOWN:
|
||||||
move_cursor_relative(&activeEditor, activeEditor.max_lines_display, 0, true, renderer);
|
move_cursor_relative(&activeEditor, activeEditor.displayLineCount, 0, true, renderer);
|
||||||
|
moved = true;
|
||||||
break;
|
break;
|
||||||
case SDLK_LEFT:
|
case SDLK_LEFT:
|
||||||
move_cursor_relative(&activeEditor, 0, -1, false, renderer);
|
move_cursor_relative(&activeEditor, 0, -1, false, renderer);
|
||||||
|
moved = true;
|
||||||
break;
|
break;
|
||||||
case SDLK_HOME:
|
case SDLK_HOME:
|
||||||
if (keyMod & KMOD_CTRL) {
|
if (keyMod & KMOD_CTRL) {
|
||||||
move_cursor(&activeEditor, 0, 0, false, renderer);
|
move_cursor(&activeEditor, 0, 0, false, renderer);
|
||||||
|
moved = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
move_cursor(&activeEditor, activeEditor.cursor_line, 0, false, renderer);
|
move_cursor(&activeEditor, activeEditor.cursor_line, 0, false, renderer);
|
||||||
|
moved = true;
|
||||||
break;
|
break;
|
||||||
case SDLK_RIGHT:
|
case SDLK_RIGHT:
|
||||||
move_cursor_relative(&activeEditor, 0, 1, false, renderer);
|
move_cursor_relative(&activeEditor, 0, 1, false, renderer);
|
||||||
|
moved = true;
|
||||||
break;
|
break;
|
||||||
case SDLK_END:
|
case SDLK_END:
|
||||||
int lineLen = strlen(activeEditor.lines[activeEditor.cursor_line].text);
|
int lineLen = strlen(activeEditor.lines[activeEditor.cursor_line].text);
|
||||||
if (keyMod & KMOD_CTRL) {
|
if (keyMod & KMOD_CTRL) {
|
||||||
move_cursor(&activeEditor, activeEditor.line_count, lineLen, false, renderer);
|
move_cursor(&activeEditor, activeEditor.maxLines - 1, lineLen, false, renderer);
|
||||||
|
moved = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
move_cursor(&activeEditor, activeEditor.cursor_line, lineLen, false, renderer);
|
move_cursor(&activeEditor, activeEditor.cursor_line, lineLen, false, renderer);
|
||||||
|
moved = true;
|
||||||
break;
|
break;
|
||||||
case SDLK_F9:
|
case SDLK_F9:
|
||||||
cpu.mode ^= CPU_MODE_LOOP;
|
cpu.mode ^= CPU_MODE_LOOP;
|
||||||
updateState();
|
updateState(false);
|
||||||
return 1;
|
return 1;
|
||||||
case SDLK_F8:
|
case SDLK_F8:
|
||||||
if (++cpuSpeedTemp == 3) {
|
if (++cpuSpeedTemp == 3) {
|
||||||
@@ -336,7 +351,7 @@ int processEvent(SDL_Event e) {
|
|||||||
}
|
}
|
||||||
cpu.mode &= ~(CPU_MODE_SECOND | CPU_MODE_STEP);
|
cpu.mode &= ~(CPU_MODE_SECOND | CPU_MODE_STEP);
|
||||||
cpu.mode |= cpuSpeedTemp << 4;
|
cpu.mode |= cpuSpeedTemp << 4;
|
||||||
updateState();
|
updateState(false);
|
||||||
return 1;
|
return 1;
|
||||||
case SDLK_F5:
|
case SDLK_F5:
|
||||||
compile(!(keyMod & KMOD_CTRL));
|
compile(!(keyMod & KMOD_CTRL));
|
||||||
@@ -345,7 +360,7 @@ int processEvent(SDL_Event e) {
|
|||||||
cpu.pc = 0;
|
cpu.pc = 0;
|
||||||
}
|
}
|
||||||
cpu.mode &= ~(CPU_MODE_HALTED | CPU_MODE_PAUSED | CPU_MODE_ERROR);
|
cpu.mode &= ~(CPU_MODE_HALTED | CPU_MODE_PAUSED | CPU_MODE_ERROR);
|
||||||
updateState();
|
updateState(false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_ESCAPE:
|
case SDLK_ESCAPE:
|
||||||
@@ -353,7 +368,7 @@ int processEvent(SDL_Event e) {
|
|||||||
if (keyMod & (KMOD_CTRL | KMOD_SHIFT)) {
|
if (keyMod & (KMOD_CTRL | KMOD_SHIFT)) {
|
||||||
cpu.mode |= CPU_MODE_HALTED;
|
cpu.mode |= CPU_MODE_HALTED;
|
||||||
}
|
}
|
||||||
updateState();
|
updateState(false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_s:
|
case SDLK_s:
|
||||||
@@ -373,26 +388,30 @@ int processEvent(SDL_Event e) {
|
|||||||
if (keyMod & KMOD_CTRL) {
|
if (keyMod & KMOD_CTRL) {
|
||||||
FILE *fptr;
|
FILE *fptr;
|
||||||
char fname[20];
|
char fname[20];
|
||||||
sscanf(editors[0].lines[0].text, "%s", fname);
|
sscanf(editors[0].lines[editors[0].cursor_line].text, "%s", fname);
|
||||||
toLowerCase(fname);
|
toLowerCase(fname);
|
||||||
strcat(fname, ".bsm");
|
strcat(fname, ".bsm");
|
||||||
fptr = fopen(fname, "r");
|
fptr = fopen(fname, "r");
|
||||||
|
if (fptr) {
|
||||||
char *prog = read_file_as_string(fname);
|
char *prog = read_file_as_string(fname);
|
||||||
fill_editor_from_string(&editors[0], prog, renderer);
|
toUpperCase(prog);
|
||||||
|
fill_editor_from_string(&editors[0], prog, 0, true, renderer);
|
||||||
free(prog);
|
free(prog);
|
||||||
fputs(editors[0].outputString, fptr);
|
|
||||||
fclose(fptr);
|
fclose(fptr);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDLK_BACKSPACE:
|
case SDLK_BACKSPACE:
|
||||||
if (!activeEditor.readOnly) {
|
if (!activeEditor.readOnly) {
|
||||||
remove_character(&activeEditor, false, renderer);
|
remove_character(&activeEditor, false, renderer);
|
||||||
|
moved = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDLK_DELETE:
|
case SDLK_DELETE:
|
||||||
if (!activeEditor.readOnly) {
|
if (!activeEditor.readOnly) {
|
||||||
remove_character(&activeEditor, true, renderer);
|
remove_character(&activeEditor, true, renderer);
|
||||||
|
moved = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDLK_RETURN:
|
case SDLK_RETURN:
|
||||||
@@ -403,6 +422,7 @@ int processEvent(SDL_Event e) {
|
|||||||
}
|
}
|
||||||
if (!activeEditor.readOnly) {
|
if (!activeEditor.readOnly) {
|
||||||
insert_line_rel(&activeEditor, renderer);
|
insert_line_rel(&activeEditor, renderer);
|
||||||
|
moved = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDLK_TAB:
|
case SDLK_TAB:
|
||||||
@@ -415,6 +435,9 @@ int processEvent(SDL_Event e) {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (moved && &activeEditor == &memoryViewer) {
|
||||||
|
updateState(false);
|
||||||
|
}
|
||||||
} else if (e.type == SDL_TEXTINPUT) {
|
} else if (e.type == SDL_TEXTINPUT) {
|
||||||
for (int i = 0; e.text.text[i] != '\0'; i++) { // Iterate over the input string
|
for (int i = 0; e.text.text[i] != '\0'; i++) { // Iterate over the input string
|
||||||
char keySym = e.text.text[i];
|
char keySym = e.text.text[i];
|
||||||
@@ -458,18 +481,18 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
|
|||||||
|
|
||||||
if (!(cpu.mode & (CPU_MODE_HALTED | CPU_MODE_PAUSED | CPU_MODE_ERROR))) {
|
if (!(cpu.mode & (CPU_MODE_HALTED | CPU_MODE_PAUSED | CPU_MODE_ERROR))) {
|
||||||
if (cpu.mode & CPU_MODE_SECOND) {
|
if (cpu.mode & CPU_MODE_SECOND) {
|
||||||
if (frames % 60) {
|
if (!(frames % 60)) {
|
||||||
step(&cpu);
|
step(&cpu);
|
||||||
updateState();
|
updateState(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
step(&cpu);
|
step(&cpu);
|
||||||
updateState();
|
updateState(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpu.mode & CPU_MODE_STEP) {
|
if (cpu.mode & CPU_MODE_STEP) {
|
||||||
cpu.mode |= CPU_MODE_PAUSED;
|
cpu.mode |= CPU_MODE_PAUSED;
|
||||||
updateState();
|
updateState(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end = SDL_GetTicks64();
|
end = SDL_GetTicks64();
|
||||||
@@ -477,7 +500,7 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
|
|||||||
if (timeNeeded < delayNeeded) {
|
if (timeNeeded < delayNeeded) {
|
||||||
SDL_Delay(delayNeeded - timeNeeded);
|
SDL_Delay(delayNeeded - timeNeeded);
|
||||||
} else {
|
} else {
|
||||||
printf("%lu", timeNeeded);
|
printf("%lu\n", timeNeeded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,11 +512,15 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
|
|||||||
destroyFont(&fonts[i]);
|
destroyFont(&fonts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
puts(SDL_GetError());
|
||||||
|
|
||||||
|
//SDL_DestroyRenderer(renderer);
|
||||||
|
|
||||||
//Destroy window
|
//Destroy window
|
||||||
SDL_DestroyWindow(window);
|
//SDL_DestroyWindow(window);
|
||||||
|
|
||||||
//Quit SDL subsystems
|
//Quit SDL subsystems
|
||||||
SDL_Quit();
|
//SDL_Quit();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@@ -6,8 +6,8 @@
|
|||||||
#include "cpustatusui.h"
|
#include "cpustatusui.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
|
||||||
SDL_Texture *renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont,
|
void renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont,
|
||||||
SDL_Renderer *renderer) {
|
SDL_Renderer *renderer, SDL_Texture **out) {
|
||||||
|
|
||||||
CPUStatusPart *stats = NULL;
|
CPUStatusPart *stats = NULL;
|
||||||
int statsCount = 0;
|
int statsCount = 0;
|
||||||
@@ -16,12 +16,14 @@ SDL_Texture *renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont,
|
|||||||
getStats(cpu, &stats, &statsCount);
|
getStats(cpu, &stats, &statsCount);
|
||||||
|
|
||||||
const int padding = 4;
|
const int padding = 4;
|
||||||
const int oneFieldW = (titleFont->size + 1) * (sizeof(stats[0].value) - 1) + padding - 1;
|
const int oneFieldW = (titleFont->size + 1) * (sizeof(stats[0].value)) + padding - 1;
|
||||||
const int oneFieldH = (titleFont->size + 1) * 2 + (valueFont->size + 1);
|
const int oneFieldH = (titleFont->size + 1) * 2 + (valueFont->size + 1);
|
||||||
SDL_Texture *out = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
|
if (!*out) {
|
||||||
|
*out = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
|
||||||
oneFieldW * statsCount, oneFieldH);
|
oneFieldW * statsCount, oneFieldH);
|
||||||
|
}
|
||||||
|
|
||||||
SDL_SetRenderTarget(renderer, out);
|
SDL_SetRenderTarget(renderer, *out);
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
@@ -61,7 +63,7 @@ SDL_Texture *renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont,
|
|||||||
}
|
}
|
||||||
|
|
||||||
SDL_SetRenderTarget(renderer, NULL);
|
SDL_SetRenderTarget(renderer, NULL);
|
||||||
return out;
|
free(stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getStats(CPU *cpu, CPUStatusPart **cpuStatus, int *cpuStatusCount) {
|
void getStats(CPU *cpu, CPUStatusPart **cpuStatus, int *cpuStatusCount) {
|
||||||
@@ -81,27 +83,27 @@ void getStats(CPU *cpu, CPUStatusPart **cpuStatus, int *cpuStatusCount) {
|
|||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
strncpy((*cpuStatus)[index].name, "PC", sizeof((*cpuStatus)[index].name));
|
strncpy((*cpuStatus)[index].name, "PCNT", sizeof((*cpuStatus)[index].name));
|
||||||
(*cpuStatus)[index].value = cpu->pc;
|
(*cpuStatus)[index].value = cpu->pc;
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
strncpy((*cpuStatus)[index].name, "SP", sizeof((*cpuStatus)[index].name));
|
strncpy((*cpuStatus)[index].name, "SPTR", sizeof((*cpuStatus)[index].name));
|
||||||
(*cpuStatus)[index].value = cpu->stack_ptr;
|
(*cpuStatus)[index].value = cpu->stack_ptr;
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
strncpy((*cpuStatus)[index].name, "FLG", sizeof((*cpuStatus)[index].name));
|
strncpy((*cpuStatus)[index].name, "FLAG", sizeof((*cpuStatus)[index].name));
|
||||||
(*cpuStatus)[index].value = cpu->flags;
|
(*cpuStatus)[index].value = cpu->flags;
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
strncpy((*cpuStatus)[index].name, "MOD", sizeof((*cpuStatus)[index].name));
|
strncpy((*cpuStatus)[index].name, "MODE", sizeof((*cpuStatus)[index].name));
|
||||||
(*cpuStatus)[index].value = cpu->mode;
|
(*cpuStatus)[index].value = cpu->mode;
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
strncpy((*cpuStatus)[index].name, "CYC", sizeof((*cpuStatus)[index].name));
|
strncpy((*cpuStatus)[index].name, "CYCL", sizeof((*cpuStatus)[index].name));
|
||||||
(*cpuStatus)[index].value = cpu->cycle;
|
(*cpuStatus)[index].value = cpu->cycle;
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
for (int i = 0; i < 25; i++) {
|
for (int i = 0; i < 18; i++) {
|
||||||
snprintf((*cpuStatus)[index].name, sizeof((*cpuStatus)[index].name), "R%d", i);
|
snprintf((*cpuStatus)[index].name, sizeof((*cpuStatus)[index].name), "R%d", i);
|
||||||
(*cpuStatus)[index].value = cpu->regs[i];
|
(*cpuStatus)[index].value = cpu->regs[i];
|
||||||
index++;
|
index++;
|
||||||
@@ -110,7 +112,7 @@ void getStats(CPU *cpu, CPUStatusPart **cpuStatus, int *cpuStatusCount) {
|
|||||||
*cpuStatusCount = index; // Store the actual number of status parts
|
*cpuStatusCount = index; // Store the actual number of status parts
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Texture *renderState(CPU *cpu, BitmapFont *titleFont, SDL_Renderer *renderer) {
|
void renderState(CPU *cpu, BitmapFont *titleFont, SDL_Renderer *renderer, SDL_Texture **out) {
|
||||||
|
|
||||||
// Render the value
|
// Render the value
|
||||||
char valueStr[20] = "";
|
char valueStr[20] = "";
|
||||||
@@ -141,10 +143,12 @@ SDL_Texture *renderState(CPU *cpu, BitmapFont *titleFont, SDL_Renderer *renderer
|
|||||||
const int oneFieldW = (titleFont->size + 1);
|
const int oneFieldW = (titleFont->size + 1);
|
||||||
const int allFieldW = oneFieldW * strlen(valueStr);
|
const int allFieldW = oneFieldW * strlen(valueStr);
|
||||||
const int oneFieldH = (titleFont->size + 1);
|
const int oneFieldH = (titleFont->size + 1);
|
||||||
SDL_Texture *out = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
|
if (!*out) {
|
||||||
|
*out = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
|
||||||
allFieldW, oneFieldH);
|
allFieldW, oneFieldH);
|
||||||
|
}
|
||||||
|
|
||||||
SDL_SetRenderTarget(renderer, out);
|
SDL_SetRenderTarget(renderer, *out);
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
@@ -164,5 +168,4 @@ SDL_Texture *renderState(CPU *cpu, BitmapFont *titleFont, SDL_Renderer *renderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
SDL_SetRenderTarget(renderer, NULL);
|
SDL_SetRenderTarget(renderer, NULL);
|
||||||
return out;
|
|
||||||
}
|
}
|
@@ -9,14 +9,14 @@
|
|||||||
#include "../cpu/core.h"
|
#include "../cpu/core.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[4];
|
char name[5];
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
} CPUStatusPart;
|
} CPUStatusPart;
|
||||||
|
|
||||||
SDL_Texture *renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont,
|
void renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont,
|
||||||
SDL_Renderer *renderer);
|
SDL_Renderer *renderer, SDL_Texture ** out);
|
||||||
|
|
||||||
SDL_Texture *renderState(CPU *cpu, BitmapFont *titleFont, SDL_Renderer *renderer);
|
void renderState(CPU *cpu, BitmapFont *titleFont, SDL_Renderer *renderer, SDL_Texture **out);
|
||||||
|
|
||||||
void getStats(CPU *cpu, CPUStatusPart **cpuStatus, int *cpuStatusCount);
|
void getStats(CPU *cpu, CPUStatusPart **cpuStatus, int *cpuStatusCount);
|
||||||
|
|
||||||
|
@@ -12,8 +12,12 @@ prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file, uint8_t
|
|||||||
out.color = (SDL_Color) {r, g, b, a};
|
out.color = (SDL_Color) {r, g, b, a};
|
||||||
unsigned int i = 1;
|
unsigned int i = 1;
|
||||||
do {
|
do {
|
||||||
|
if (i == 173) { //specifically this char is 0 width (IDK why)
|
||||||
|
out.surface[i] = SDL_CreateRGBSurface(0,pxSize,pxSize,32,0,0,0,0);
|
||||||
|
} else {
|
||||||
char tmpOut[2] = {i, 0};
|
char tmpOut[2] = {i, 0};
|
||||||
out.surface[i] = TTF_RenderText_Solid(gFont, tmpOut, out.color);
|
out.surface[i] = TTF_RenderText_Solid(gFont, tmpOut, out.color);
|
||||||
|
}
|
||||||
out.texture[i] = SDL_CreateTextureFromSurface(renderer, out.surface[i]);
|
out.texture[i] = SDL_CreateTextureFromSurface(renderer, out.surface[i]);
|
||||||
i++;
|
i++;
|
||||||
} while (i < 256);
|
} while (i < 256);
|
||||||
|
@@ -6,44 +6,39 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#define BYTES_PER_LINE 16 // Adjust for different widths
|
#define BYTES_PER_LINE 16 // Adjust for different widths
|
||||||
|
|
||||||
|
|
||||||
char *hexdump_to_string(const unsigned char *data, size_t size) {
|
char *hexdump_to_string(const unsigned char *data, uint32_t start, uint32_t end) {
|
||||||
|
if (start >= end) return NULL; // Invalid range
|
||||||
|
|
||||||
// Estimate max output size: each line is approx. 80 chars
|
// Estimate max output size: each line is approx. 80 chars
|
||||||
size_t estimated_size = (size / BYTES_PER_LINE + 1) * 80;
|
uint32_t estimated_size = ((end - start) / BYTES_PER_LINE + 1) * 60;
|
||||||
|
|
||||||
// Allocate memory for output string
|
// Allocate memory for output string
|
||||||
char *output = malloc(estimated_size);
|
char *output = malloc(estimated_size);
|
||||||
if (!output) return NULL;
|
if (!output) return NULL;
|
||||||
|
|
||||||
size_t offset = 0; // Track the write position
|
uint32_t out_offset = 0; // Tracks position in output buffer
|
||||||
|
|
||||||
for (size_t i = 0; i < size; i += BYTES_PER_LINE) {
|
for (uint32_t i = start; i < end; i += BYTES_PER_LINE) {
|
||||||
offset += snprintf(output + offset, estimated_size - offset, "%08zx ", i);
|
// Print offset
|
||||||
|
out_offset += snprintf(output + out_offset, estimated_size - out_offset, "%07x ", i);
|
||||||
|
|
||||||
// Print hex values
|
// Print hex values
|
||||||
for (size_t j = 0; j < BYTES_PER_LINE; j++) {
|
for (uint32_t j = 0; j < BYTES_PER_LINE; j++) {
|
||||||
if (i + j < size)
|
if (i + j < end)
|
||||||
offset += snprintf(output + offset, estimated_size - offset, "%02x ", data[i + j]);
|
out_offset += snprintf(output + out_offset, estimated_size - out_offset, "%02x ", data[i + j]);
|
||||||
else
|
else
|
||||||
offset += snprintf(output + offset, estimated_size - offset, " "); // Padding
|
out_offset += snprintf(output + out_offset, estimated_size - out_offset, " "); // Padding
|
||||||
if (j == 7) offset += snprintf(output + offset, estimated_size - offset, " "); // Extra space
|
if (j == 7)
|
||||||
|
out_offset += snprintf(output + out_offset, estimated_size - out_offset, " "); // Extra space
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += snprintf(output + offset, estimated_size - offset, " |");
|
out_offset += snprintf(output + out_offset, estimated_size - out_offset, "\n");
|
||||||
|
|
||||||
// Print ASCII representation
|
|
||||||
for (size_t j = 0; j < BYTES_PER_LINE; j++) {
|
|
||||||
if (i + j < size)
|
|
||||||
offset += snprintf(output + offset, estimated_size - offset, "%c",
|
|
||||||
isprint(data[i + j]) ? data[i + j] : '.');
|
|
||||||
else
|
|
||||||
offset += snprintf(output + offset, estimated_size - offset, " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += snprintf(output + offset, estimated_size - offset, "|\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
@@ -6,7 +6,8 @@
|
|||||||
#define RISCB_HEXDUMP_H
|
#define RISCB_HEXDUMP_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
char *hexdump_to_string(const unsigned char *data, size_t size);
|
char *hexdump_to_string(const unsigned char *data, uint32_t start, uint32_t end);
|
||||||
|
|
||||||
#endif //RISCB_HEXDUMP_H
|
#endif //RISCB_HEXDUMP_H
|
||||||
|
@@ -5,13 +5,14 @@
|
|||||||
|
|
||||||
#include "texteditor.h"
|
#include "texteditor.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
#include "../cpu/core.h"
|
||||||
|
|
||||||
// Initialize the text editor with dynamic sizes.
|
// Initialize the text editor with dynamic sizes.
|
||||||
void init_editor(TextEditor *editor, BitmapFont *font, int x, int y, SDL_Renderer *renderer,
|
void init_editor(TextEditor *editor, BitmapFont *font, int x, int y, SDL_Renderer *renderer,
|
||||||
int max_line_width, int max_lines_asm, int max_lines_display, bool readOnly) {
|
int max_line_width, int max_lines_asm, int max_lines_display, bool readOnly) {
|
||||||
editor->max_line_width = max_line_width;
|
editor->max_line_width = max_line_width;
|
||||||
editor->max_lines_asm = max_lines_asm;
|
editor->maxLines = max_lines_asm;
|
||||||
editor->max_lines_display = max_lines_display;
|
editor->displayLineCount = max_lines_display;
|
||||||
editor->line_count = 0;
|
editor->line_count = 0;
|
||||||
editor->cursor_line = 0;
|
editor->cursor_line = 0;
|
||||||
editor->cursor_line_offset = 0;
|
editor->cursor_line_offset = 0;
|
||||||
@@ -22,20 +23,22 @@ void init_editor(TextEditor *editor, BitmapFont *font, int x, int y, SDL_Rendere
|
|||||||
editor->outRect = malloc(sizeof(SDL_Rect));
|
editor->outRect = malloc(sizeof(SDL_Rect));
|
||||||
editor->cursorRect = malloc(sizeof(SDL_Rect));
|
editor->cursorRect = malloc(sizeof(SDL_Rect));
|
||||||
editor->rect = malloc(sizeof(SDL_Rect));
|
editor->rect = malloc(sizeof(SDL_Rect));
|
||||||
|
editor->highlightedLineRect = malloc(sizeof(SDL_Rect));
|
||||||
|
|
||||||
memset(editor->outRect, 0, sizeof(SDL_Rect));
|
memset(editor->outRect, 0, sizeof(SDL_Rect));
|
||||||
memset(editor->cursorRect, 0, sizeof(SDL_Rect));
|
memset(editor->cursorRect, 0, sizeof(SDL_Rect));
|
||||||
memset(editor->rect, 0, sizeof(SDL_Rect));
|
memset(editor->rect, 0, sizeof(SDL_Rect));
|
||||||
|
memset(editor->highlightedLineRect, 0, sizeof(SDL_Rect));
|
||||||
|
|
||||||
|
|
||||||
// Allocate dynamic array for lines.
|
// Allocate dynamic array for lines.
|
||||||
editor->lines = (Line *) malloc(sizeof(Line) * editor->max_lines_asm);
|
editor->lines = (Line *) malloc(sizeof(Line) * editor->maxLines);
|
||||||
if (!editor->lines) {
|
if (!editor->lines) {
|
||||||
fprintf(stderr, "Failed to allocate memory for lines.\n");
|
fprintf(stderr, "Failed to allocate memory for lines.\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
// For each line, allocate memory for the text (including space for '\0')
|
// For each line, allocate memory for the text (including space for '\0')
|
||||||
for (int i = 0; i < editor->max_lines_asm; i++) {
|
for (int i = 0; i < editor->maxLines; i++) {
|
||||||
editor->lines[i].text = (char *) malloc(sizeof(char) * (editor->max_line_width + 1));
|
editor->lines[i].text = (char *) malloc(sizeof(char) * (editor->max_line_width + 1));
|
||||||
if (!editor->lines[i].text) {
|
if (!editor->lines[i].text) {
|
||||||
fprintf(stderr, "Failed to allocate memory for line %d.\n", i);
|
fprintf(stderr, "Failed to allocate memory for line %d.\n", i);
|
||||||
@@ -46,8 +49,8 @@ void init_editor(TextEditor *editor, BitmapFont *font, int x, int y, SDL_Rendere
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocate output and display strings.
|
// Allocate output and display strings.
|
||||||
editor->outputString = (char *) malloc(sizeof(char) * (editor->max_line_width * editor->max_lines_asm + 1));
|
editor->outputString = (char *) malloc(sizeof(char) * (editor->max_line_width * editor->maxLines + 1));
|
||||||
editor->displayString = (char *) malloc(sizeof(char) * (editor->max_line_width * editor->max_lines_display + 1));
|
editor->displayString = (char *) malloc(sizeof(char) * (editor->max_line_width * editor->displayLineCount + 1));
|
||||||
if (!editor->outputString || !editor->displayString) {
|
if (!editor->outputString || !editor->displayString) {
|
||||||
fprintf(stderr, "Failed to allocate memory for output/display strings.\n");
|
fprintf(stderr, "Failed to allocate memory for output/display strings.\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@@ -60,21 +63,26 @@ void init_editor(TextEditor *editor, BitmapFont *font, int x, int y, SDL_Rendere
|
|||||||
editor->lines[1].active = 1;
|
editor->lines[1].active = 1;
|
||||||
editor->line_count = 2;
|
editor->line_count = 2;
|
||||||
|
|
||||||
// Set up the editor rectangle based on font size and dynamic max_line_width and max_lines_display.
|
// Set up the editor rectangle based on font size and dynamic max_line_width and displayLineCount.
|
||||||
editor->rect->x = 2;
|
editor->rect->x = 2;
|
||||||
editor->rect->y = 2;
|
editor->rect->y = 2;
|
||||||
editor->rect->w = editor->max_line_width * (font->size + 1) + ((font->size + 1) / 2);
|
editor->rect->w = editor->max_line_width * (font->size + 1) + ((font->size + 1) / 2);
|
||||||
editor->rect->h = editor->max_lines_display * (font->size + 1) + 2;
|
editor->rect->h = editor->displayLineCount * (font->size + 1) + 2;
|
||||||
editor->outRect->w = editor->rect->w;
|
editor->outRect->w = editor->rect->w;
|
||||||
editor->outRect->h = editor->rect->h;
|
editor->outRect->h = editor->rect->h;
|
||||||
editor->outRect->x = x;
|
editor->outRect->x = x;
|
||||||
editor->outRect->y = y;
|
editor->outRect->y = y;
|
||||||
|
|
||||||
|
editor->highlightedLineRect->x = 2;
|
||||||
|
editor->highlightedLineRect->y = 2;
|
||||||
|
editor->highlightedLineRect->w = editor->outRect->w - (2 * editor->highlightedLineRect->x);
|
||||||
|
editor->highlightedLineRect->h = editor->font->size;
|
||||||
|
|
||||||
editor->cursorRect->x = 3 + editor->cursor_pos * font->size + editor->outRect->x;
|
editor->cursorRect->x = 3 + editor->cursor_pos * font->size + editor->outRect->x;
|
||||||
editor->cursorRect->y =
|
editor->cursorRect->y =
|
||||||
2 + (editor->cursor_line - editor->cursor_line_offset) * (font->size + 1) + editor->outRect->y;
|
2 + (editor->cursor_line - editor->cursor_line_offset) * (font->size + 1) + editor->outRect->y;
|
||||||
|
|
||||||
editor->cursorRect->w = 2;
|
editor->cursorRect->w = editor->font->size;
|
||||||
editor->cursorRect->h = editor->font->size;
|
editor->cursorRect->h = editor->font->size;
|
||||||
|
|
||||||
// Create texture for rendering.
|
// Create texture for rendering.
|
||||||
@@ -87,9 +95,8 @@ void init_editor(TextEditor *editor, BitmapFont *font, int x, int y, SDL_Rendere
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert a new line at a specific position.
|
|
||||||
void insert_line(TextEditor *editor, int position, const char *text, SDL_Renderer *renderer) {
|
void insert_line(TextEditor *editor, int position, const char *text, SDL_Renderer *renderer) {
|
||||||
if (editor->line_count >= editor->max_lines_asm || position < 0 || position > editor->line_count) {
|
if (editor->line_count >= editor->maxLines || position < 0 || position > editor->line_count) {
|
||||||
printf("Invalid position or max lines reached!\n");
|
printf("Invalid position or max lines reached!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -111,7 +118,16 @@ void insert_line(TextEditor *editor, int position, const char *text, SDL_Rendere
|
|||||||
}
|
}
|
||||||
|
|
||||||
void insert_line_rel(TextEditor *editor, SDL_Renderer *renderer) {
|
void insert_line_rel(TextEditor *editor, SDL_Renderer *renderer) {
|
||||||
insert_line(editor, editor->cursor_line + (editor->cursor_pos ? 1 : 0), "", renderer);
|
int line = editor->cursor_line;
|
||||||
|
int pos = editor->cursor_pos;
|
||||||
|
char *current_text = editor->lines[line].text;
|
||||||
|
|
||||||
|
// Split the current line at the cursor position
|
||||||
|
char new_line_text[editor->max_line_width + 1];
|
||||||
|
strcpy(new_line_text, ¤t_text[pos]); // Copy the text after cursor to the new line
|
||||||
|
current_text[pos] = '\0'; // Truncate the current line at cursor position
|
||||||
|
|
||||||
|
insert_line(editor, line + 1, new_line_text, renderer);
|
||||||
editor->cursor_pos = 0;
|
editor->cursor_pos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,11 +170,27 @@ void remove_character(TextEditor *editor, bool isDelete, SDL_Renderer *renderer)
|
|||||||
for (int i = editor->cursor_pos; i < len; i++) {
|
for (int i = editor->cursor_pos; i < len; i++) {
|
||||||
line->text[i] = line->text[i + 1];
|
line->text[i] = line->text[i + 1];
|
||||||
}
|
}
|
||||||
|
} else if (editor->cursor_pos == len && editor->cursor_line < editor->line_count - 1) {
|
||||||
|
// Merge next line with the current line when pressing delete at the end
|
||||||
|
strcat(line->text, editor->lines[editor->cursor_line + 1].text);
|
||||||
|
|
||||||
|
// Shift remaining lines up
|
||||||
|
for (int i = editor->cursor_line + 1; i < editor->line_count - 1; i++) {
|
||||||
|
strcpy(editor->lines[i].text, editor->lines[i + 1].text);
|
||||||
|
editor->lines[i].active = editor->lines[i + 1].active;
|
||||||
|
}
|
||||||
|
editor->lines[editor->line_count - 1].text[0] = '\0';
|
||||||
|
editor->lines[editor->line_count - 1].active = 0;
|
||||||
|
editor->line_count--;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Backspace behavior (delete character before cursor)
|
// Backspace behavior (delete character before cursor)
|
||||||
if (editor->cursor_pos == 0 && editor->line_count > 1) {
|
if (editor->cursor_pos == 0 && editor->cursor_line > 0) {
|
||||||
// Merge with the previous line
|
// Append current line to previous line
|
||||||
|
int prev_len = strlen(editor->lines[editor->cursor_line - 1].text);
|
||||||
|
strcat(editor->lines[editor->cursor_line - 1].text, line->text);
|
||||||
|
|
||||||
|
// Shift lines up
|
||||||
for (int i = editor->cursor_line; i < editor->line_count - 1; i++) {
|
for (int i = editor->cursor_line; i < editor->line_count - 1; i++) {
|
||||||
strcpy(editor->lines[i].text, editor->lines[i + 1].text);
|
strcpy(editor->lines[i].text, editor->lines[i + 1].text);
|
||||||
editor->lines[i].active = editor->lines[i + 1].active;
|
editor->lines[i].active = editor->lines[i + 1].active;
|
||||||
@@ -166,10 +198,10 @@ void remove_character(TextEditor *editor, bool isDelete, SDL_Renderer *renderer)
|
|||||||
editor->lines[editor->line_count - 1].text[0] = '\0';
|
editor->lines[editor->line_count - 1].text[0] = '\0';
|
||||||
editor->lines[editor->line_count - 1].active = 0;
|
editor->lines[editor->line_count - 1].active = 0;
|
||||||
editor->line_count--;
|
editor->line_count--;
|
||||||
if (editor->cursor_line >= editor->line_count) {
|
|
||||||
editor->cursor_line = editor->line_count - 1;
|
// Move cursor to the end of the previous line
|
||||||
}
|
editor->cursor_line--;
|
||||||
editor->cursor_pos = strlen(editor->lines[editor->cursor_line].text);
|
editor->cursor_pos = prev_len;
|
||||||
} else if (editor->cursor_pos > 0) {
|
} else if (editor->cursor_pos > 0) {
|
||||||
for (int i = editor->cursor_pos - 1; i < len; i++) {
|
for (int i = editor->cursor_pos - 1; i < len; i++) {
|
||||||
line->text[i] = line->text[i + 1];
|
line->text[i] = line->text[i + 1];
|
||||||
@@ -191,7 +223,14 @@ void move_cursor_relative(TextEditor *editor, int line_offset, int pos_offset, b
|
|||||||
|
|
||||||
void move_cursor(TextEditor *editor, int new_line, int new_pos, bool keepPos, SDL_Renderer *renderer) {
|
void move_cursor(TextEditor *editor, int new_line, int new_pos, bool keepPos, SDL_Renderer *renderer) {
|
||||||
if (new_line < 0) new_line = 0;
|
if (new_line < 0) new_line = 0;
|
||||||
if (new_line >= editor->line_count) new_line = editor->line_count - 1;
|
int trgt = editor->line_count - editor->displayLineCount;
|
||||||
|
if (trgt < 0) {
|
||||||
|
trgt = 0;
|
||||||
|
}
|
||||||
|
if (new_line >= trgt && new_line >= editor->line_count) {
|
||||||
|
new_line = editor->line_count -
|
||||||
|
1;
|
||||||
|
}
|
||||||
|
|
||||||
if (keepPos) {
|
if (keepPos) {
|
||||||
editor->cursor_line_offset = new_line;
|
editor->cursor_line_offset = new_line;
|
||||||
@@ -200,8 +239,15 @@ void move_cursor(TextEditor *editor, int new_line, int new_pos, bool keepPos, SD
|
|||||||
if (new_line < editor->cursor_line_offset) {
|
if (new_line < editor->cursor_line_offset) {
|
||||||
editor->cursor_line_offset = new_line;
|
editor->cursor_line_offset = new_line;
|
||||||
}
|
}
|
||||||
if (new_line >= editor->cursor_line_offset + editor->max_lines_display) {
|
if (new_line >= editor->cursor_line_offset + editor->displayLineCount) {
|
||||||
editor->cursor_line_offset = new_line - editor->max_lines_display + 1;
|
editor->cursor_line_offset = new_line - editor->displayLineCount + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editor->cursor_line_offset >= editor->line_count - editor->displayLineCount) {
|
||||||
|
editor->cursor_line_offset = editor->line_count - editor->displayLineCount;
|
||||||
|
}
|
||||||
|
if (editor->cursor_line_offset < 0) {
|
||||||
|
editor->cursor_line_offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int line_length = strlen(editor->lines[new_line].text);
|
int line_length = strlen(editor->lines[new_line].text);
|
||||||
@@ -219,7 +265,7 @@ void generate_string_display(TextEditor *editor, SDL_Renderer *renderer) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int end_line = editor->cursor_line_offset + editor->max_lines_display;
|
int end_line = editor->cursor_line_offset + editor->displayLineCount;
|
||||||
if (end_line > editor->line_count)
|
if (end_line > editor->line_count)
|
||||||
end_line = editor->line_count;
|
end_line = editor->line_count;
|
||||||
|
|
||||||
@@ -227,7 +273,7 @@ void generate_string_display(TextEditor *editor, SDL_Renderer *renderer) {
|
|||||||
editor->displayString[0] = '\0';
|
editor->displayString[0] = '\0';
|
||||||
|
|
||||||
SDL_SetRenderTarget(renderer, editor->texture);
|
SDL_SetRenderTarget(renderer, editor->texture);
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
|
||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
SDL_Rect charDstRect;
|
SDL_Rect charDstRect;
|
||||||
@@ -263,7 +309,8 @@ void generate_string_display(TextEditor *editor, SDL_Renderer *renderer) {
|
|||||||
SDL_SetRenderTarget(renderer, NULL);
|
SDL_SetRenderTarget(renderer, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void editor_render(TextEditor *editor, SDL_Renderer *renderer, bool isActive, bool cursorBlink) {
|
void editor_render(TextEditor *editor, SDL_Renderer *renderer, CPU *cpu, uint8_t editorIndex, bool isActive,
|
||||||
|
bool cursorBlink) {
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
SDL_Rect bgRect;
|
SDL_Rect bgRect;
|
||||||
bgRect = *editor->outRect;
|
bgRect = *editor->outRect;
|
||||||
@@ -271,20 +318,57 @@ void editor_render(TextEditor *editor, SDL_Renderer *renderer, bool isActive, bo
|
|||||||
bgRect.y -= 6;
|
bgRect.y -= 6;
|
||||||
bgRect.w += 12;
|
bgRect.w += 12;
|
||||||
bgRect.h += 12;
|
bgRect.h += 12;
|
||||||
|
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(renderer, editor->readOnly ? 128 : 0, editor->readOnly ? 0 : 128, 64, 255);
|
SDL_SetRenderDrawColor(renderer, editor->readOnly ? 128 : 0, editor->readOnly ? 0 : 128, 64, 255);
|
||||||
SDL_RenderFillRect(renderer, &bgRect);
|
SDL_RenderFillRect(renderer, &bgRect);
|
||||||
|
|
||||||
}
|
}
|
||||||
SDL_RenderCopy(renderer, editor->texture, editor->rect, editor->outRect);
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderFillRect(renderer, editor->outRect);
|
||||||
|
|
||||||
|
uint32_t targetLine = 0;
|
||||||
|
const uint32_t instrLine = cpu->pc / CPU_INSTRUCTION_SIZE;
|
||||||
|
if (editorIndex == 0) {
|
||||||
|
targetLine = cpu->addrToLineMapper[instrLine] - editor->cursor_line_offset;
|
||||||
|
editor->highlightedLineRect->w = editor->rect->w - 1;
|
||||||
|
editor->highlightedLineRect->x = 2;
|
||||||
|
}
|
||||||
|
if (editorIndex == 1) {
|
||||||
|
targetLine = (instrLine / 2) - editor->cursor_line_offset;
|
||||||
|
editor->highlightedLineRect->w = (editor->rect->w / 5 * 2) - 2;
|
||||||
|
editor->highlightedLineRect->x =
|
||||||
|
2 + (11 * editor->font->size) + (instrLine % 2 ? (28 * editor->font->size) : 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
editor->highlightedLineRect->y = 2 + ((editor->font->size + 1) * targetLine);
|
||||||
|
SDL_Rect highlightedLineAbs = *editor->highlightedLineRect;
|
||||||
|
highlightedLineAbs.x += editor->outRect->x;
|
||||||
|
highlightedLineAbs.y += editor->outRect->y;
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 72, 64, 255);
|
||||||
|
if (targetLine >= editor->cursor_line_offset &&
|
||||||
|
targetLine < editor->cursor_line_offset + editor->displayLineCount) {
|
||||||
|
SDL_RenderFillRect(renderer, &highlightedLineAbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SDL_SetTextureBlendMode(editor
|
||||||
|
->texture, SDL_BLENDMODE_BLEND);
|
||||||
|
SDL_RenderCopy(renderer, editor
|
||||||
|
->texture, editor->rect, editor->outRect);
|
||||||
if (isActive && cursorBlink) {
|
if (isActive && cursorBlink) {
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255);
|
SDL_SetRenderDrawColor(renderer,
|
||||||
SDL_RenderFillRect(renderer, editor->cursorRect);
|
0, 255, 255, 128);
|
||||||
|
SDL_RenderFillRect(renderer, editor
|
||||||
|
->cursorRect);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_string(TextEditor *editor) {
|
void generate_string(TextEditor *editor) {
|
||||||
editor->outputString[0] = '\0';
|
editor->outputString[0] = '\0';
|
||||||
|
|
||||||
for (int i = 0; i < editor->max_lines_asm; i++) {
|
for (int i = 0; i < editor->maxLines; i++) {
|
||||||
if (editor->lines[i].active) {
|
if (editor->lines[i].active) {
|
||||||
if (strlen(editor->lines[i].text)) {
|
if (strlen(editor->lines[i].text)) {
|
||||||
strcat(editor->outputString, editor->lines[i].text);
|
strcat(editor->outputString, editor->lines[i].text);
|
||||||
@@ -294,30 +378,39 @@ void generate_string(TextEditor *editor) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill_editor_from_string(TextEditor *editor, const char *content, SDL_Renderer *renderer) {
|
void fill_editor_from_string(TextEditor *editor, const char *content, int lineStart, bool isComplete,
|
||||||
|
SDL_Renderer *renderer) {
|
||||||
if (!editor || !content) {
|
if (!editor || !content) {
|
||||||
printf("Invalid editor or content pointer!\n");
|
printf("Invalid editor or content pointer!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *str = content;
|
||||||
|
|
||||||
|
int numLines = 0;
|
||||||
|
while (*str) if (*str++ == '\n') ++numLines;
|
||||||
|
|
||||||
// Clear the current editor content
|
// Clear the current editor content
|
||||||
for (int i = 0; i < editor->max_lines_asm; i++) {
|
for (int i = lineStart; i < editor->maxLines && i < lineStart + numLines + 1; i++) {
|
||||||
editor->lines[i].text[0] = '\0';
|
editor->lines[i].text[0] = '\0';
|
||||||
editor->lines[i].active = 0;
|
editor->lines[i].active = 0;
|
||||||
}
|
}
|
||||||
editor->line_count = 0;
|
if (isComplete) {
|
||||||
editor->cursor_line = 0;
|
editor->line_count = numLines;
|
||||||
editor->cursor_pos = 0;
|
if (editor->line_count >= editor->maxLines) {
|
||||||
|
editor->line_count = editor->maxLines - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parse the content and fill the editor lines
|
// Parse the content and fill the editor lines
|
||||||
const char *ptr = content;
|
const char *ptr = content;
|
||||||
int line_index = 0;
|
int line_index = lineStart;
|
||||||
|
|
||||||
while (*ptr && line_index < editor->max_lines_asm) {
|
while (*ptr && line_index < editor->maxLines && line_index < numLines + lineStart) {
|
||||||
int char_count = 0;
|
int char_count = 0;
|
||||||
|
|
||||||
// Ensure the text buffer does not overflow
|
// Ensure the text buffer does not overflow
|
||||||
while (*ptr && *ptr != '\n' && char_count < editor->max_line_width - 1) {
|
while (*ptr && *ptr != '\n' && char_count < editor->max_line_width) {
|
||||||
editor->lines[line_index].text[char_count++] = *ptr++;
|
editor->lines[line_index].text[char_count++] = *ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,9 +421,11 @@ void fill_editor_from_string(TextEditor *editor, const char *content, SDL_Render
|
|||||||
// Move past the newline character if present
|
// Move past the newline character if present
|
||||||
if (*ptr == '\n') ptr++;
|
if (*ptr == '\n') ptr++;
|
||||||
}
|
}
|
||||||
|
editor->lines[line_index].active = 1;
|
||||||
|
|
||||||
// Update the total number of lines in use
|
// Update the total number of lines in use
|
||||||
editor->line_count = line_index;
|
//editor->line_count = line_index + (line_index < editor->maxLines - 1 ? 1 : 0);
|
||||||
|
//if (editor->line_count >= editor-> maxLines)
|
||||||
|
|
||||||
// Generate the visual representation
|
// Generate the visual representation
|
||||||
generate_string_display(editor, renderer);
|
generate_string_display(editor, renderer);
|
||||||
@@ -340,13 +435,13 @@ void fill_editor_from_string(TextEditor *editor, const char *content, SDL_Render
|
|||||||
// Free all dynamically allocated memory.
|
// Free all dynamically allocated memory.
|
||||||
void destroy_editor(TextEditor *editor) {
|
void destroy_editor(TextEditor *editor) {
|
||||||
if (editor->lines) {
|
if (editor->lines) {
|
||||||
for (int i = 0; i < editor->max_lines_asm; i++) {
|
for (int i = 0; i < editor->maxLines; i++) {
|
||||||
free(editor->lines[i].text);
|
free(editor->lines[i].text);
|
||||||
}
|
}
|
||||||
free(editor->lines);
|
free(editor->lines);
|
||||||
}
|
}
|
||||||
free(editor->outputString);
|
//free(editor->outputString);
|
||||||
free(editor->displayString);
|
//free(editor->displayString);
|
||||||
|
|
||||||
free(editor->outRect);
|
free(editor->outRect);
|
||||||
free(editor->rect);
|
free(editor->rect);
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#include <SDL2/SDL_surface.h>
|
#include <SDL2/SDL_surface.h>
|
||||||
#include <SDL2/SDL_render.h>
|
#include <SDL2/SDL_render.h>
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
#include "../cpu/core.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *text; // Dynamically allocated string for this line
|
char *text; // Dynamically allocated string for this line
|
||||||
@@ -22,25 +23,26 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
Line *lines; // Dynamic array of lines
|
Line *lines; // Dynamic array of lines
|
||||||
int line_count; // Number of active lines
|
int line_count; // Number of active lines
|
||||||
int max_lines_asm; // Maximum number of lines (e.g. assembly lines)
|
int maxLines; // Maximum number of lines (e.g. assembly lines)
|
||||||
int max_line_width; // Maximum characters per line (excluding '\0')
|
int max_line_width; // Maximum characters per line (excluding '\0')
|
||||||
int max_lines_display; // Maximum number of lines for display
|
int displayLineCount; // Maximum number of lines for display
|
||||||
|
|
||||||
int cursor_line; // Current cursor line
|
int cursor_line; // Current cursor line
|
||||||
int cursor_line_offset; // Display offset (first line in the display)
|
int cursor_line_offset; // Display offset (first line in the display)
|
||||||
int cursor_pos; // Current cursor position in line
|
int cursor_pos; // Current cursor position in line
|
||||||
|
|
||||||
char *outputString; // Dynamically allocated output string (size: max_line_width * max_lines_asm + 1)
|
char *outputString; // Dynamically allocated output string (size: max_line_width * maxLines + 1)
|
||||||
char *displayString; // Dynamically allocated display string (size: max_line_width * max_lines_display + 1)
|
char *displayString; // Dynamically allocated display string (size: max_line_width * displayLineCount + 1)
|
||||||
SDL_Rect *rect;
|
SDL_Rect *rect;
|
||||||
SDL_Rect *outRect;
|
SDL_Rect *outRect;
|
||||||
SDL_Texture *texture;
|
SDL_Texture *texture;
|
||||||
bool readOnly;
|
bool readOnly;
|
||||||
BitmapFont *font;
|
BitmapFont *font;
|
||||||
SDL_Rect *cursorRect;
|
SDL_Rect *cursorRect;
|
||||||
|
SDL_Rect *highlightedLineRect;
|
||||||
} TextEditor;
|
} TextEditor;
|
||||||
|
|
||||||
// Initialize the text editor. The parameters max_line_width, max_lines_asm, and max_lines_display
|
// Initialize the text editor. The parameters max_line_width, maxLines, and displayLineCount
|
||||||
// determine the dynamic sizes for the text editor.
|
// determine the dynamic sizes for the text editor.
|
||||||
void init_editor(TextEditor *editor, BitmapFont *font, int x, int y, SDL_Renderer *renderer,
|
void init_editor(TextEditor *editor, BitmapFont *font, int x, int y, SDL_Renderer *renderer,
|
||||||
int max_line_width, int max_lines_asm, int max_lines_display, bool readOnly);
|
int max_line_width, int max_lines_asm, int max_lines_display, bool readOnly);
|
||||||
@@ -50,7 +52,7 @@ void insert_line(TextEditor *editor, int position, const char *text, SDL_Rendere
|
|||||||
|
|
||||||
void insert_line_rel(TextEditor *editor, SDL_Renderer *renderer);
|
void insert_line_rel(TextEditor *editor, SDL_Renderer *renderer);
|
||||||
|
|
||||||
void editor_render(TextEditor *editor, SDL_Renderer *renderer, bool isActive, bool cursorBlink);
|
void editor_render(TextEditor *editor, SDL_Renderer *renderer, CPU *cpu, uint8_t editorIndex, bool isActive, bool cursorBlink);
|
||||||
|
|
||||||
void remove_character(TextEditor *editor, bool isDelete, SDL_Renderer *renderer);
|
void remove_character(TextEditor *editor, bool isDelete, SDL_Renderer *renderer);
|
||||||
|
|
||||||
@@ -64,7 +66,8 @@ void generate_string_display(TextEditor *editor, SDL_Renderer *renderer);
|
|||||||
|
|
||||||
void generate_string(TextEditor *editor);
|
void generate_string(TextEditor *editor);
|
||||||
|
|
||||||
void fill_editor_from_string(TextEditor *editor, const char *content, SDL_Renderer *renderer);
|
void fill_editor_from_string(TextEditor *editor, const char *content, int lineStart, bool isComplete,
|
||||||
|
SDL_Renderer *renderer);
|
||||||
|
|
||||||
// A cleanup function to free dynamically allocated memory.
|
// A cleanup function to free dynamically allocated memory.
|
||||||
void destroy_editor(TextEditor *editor);
|
void destroy_editor(TextEditor *editor);
|
||||||
|
Reference in New Issue
Block a user