Add highlighting, fixed len instructions and more

This commit is contained in:
2025-02-09 21:15:50 +01:00
parent 45653b6372
commit e133c2df3a
17 changed files with 753 additions and 338 deletions

View File

@@ -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 isnt purely numeric, treat it as a label. // If the operand isnt 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);
}

View File

@@ -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

View File

@@ -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++;
} }

View File

@@ -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;

View File

@@ -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

View 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

View File

@@ -0,0 +1,6 @@
TEST:
INC R1
INC R2
MOV R2 [20]
JMP TEST
HLT

4
docs/examples/test1.bsm Normal file
View File

@@ -0,0 +1,4 @@
INC R1
BRK
INC R2
HLT

195
docs/instructions.md Normal file
View 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
View File

@@ -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;
} }

View File

@@ -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;
} }

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View File

@@ -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, &current_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);

View File

@@ -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);