diff --git a/assembler/assembler.c b/assembler/assembler.c index 79b69ab..4d20403 100644 --- a/assembler/assembler.c +++ b/assembler/assembler.c @@ -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. // 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]; int addr = 0; labelCount = 0; @@ -316,152 +316,170 @@ int firstPass(const char *source) { continue; strcpy(line, rest); } - - // Parse the mnemonic and operands. - char mnemonic[32], operand1[64], operand2[64], operand3[64]; - operand1[0] = '\0'; - operand2[0] = '\0'; - int tokenCount = sscanf(line, "%31s %63[^, ] %63[^, ] %63s", - mnemonic, operand1, operand2, operand3); - - - // Use the mapper to get a base opcode. - int baseOpcode = getOpcode(mnemonic); - if (baseOpcode == -1) { - printf("Unknown instruction: %s\n", mnemonic); - continue; - } - - int size = 0; // Instruction size in bytes. - if (baseOpcode == -2) { - // MOV instruction requires further resolution. - int resolvedOpcode = resolveMOV(operand1, operand2); - if (resolvedOpcode == MOV_RN_IMM || resolvedOpcode == MOV_RN_RM) { - size = 3; // opcode (1) + reg (1) + immediate or register (1) - } else if (resolvedOpcode == MOV_RN_ADDR || resolvedOpcode == MOV_ADDR_RN) { - size = 6; // opcode (1) + one operand as register (1) and one 32-bit address (4) [+ padding if needed] - } else { - size = 3; // fallback - } - } else if (baseOpcode < 0) { - // Ambiguous instructions that use resolveALU. - // For JMP and jump-bit instructions, the jump target is in operand1. - if (baseOpcode == -11) { - // JMP: if operand1 starts with '+' or '-', it's relative. - if (operand1[0] == '+' || operand1[0] == '-') { - // resolve as JMP_REL. - int resolvedOpcode = resolveALU(baseOpcode, operand1); - size = 2; // opcode (1) + 1-byte relative offset (1) - } else { - int resolvedOpcode = resolveALU(baseOpcode, operand1); - size = 5; // opcode (1) + 32-bit absolute address (4) - } - } else if (baseOpcode == -14 || baseOpcode == -15) { - // JMPBS or JMPBC (jump if bit set/clear) - int resolvedOpcode = resolveALU(baseOpcode, operand1); - if (operand1[0] == 'R' || operand1[0] == 'r') - size = 7; // opcode (1) + register (1) + bit (1) + 32-bit jump address (4) - else - size = 10; // opcode (1) + 32-bit memory address (4) + bit (1) + 32-bit jump address (4) - } else { - // For arithmetic ALU instructions and INC/DEC, - // use operand2 to resolve. - int resolvedOpcode = resolveALU(baseOpcode, operand2); - switch (resolvedOpcode) { - case ADD_RN_RM: - case SUB_RN_RM: - case MUL_RN_RM: - case DIV_RN_RM: - case MOD_RN_RM: - case AND_RN_RM: - case OR_RN_RM: - case XOR_RN_RM: - case ADD_RN_IMM: - case SUB_RN_IMM: - case MUL_RN_IMM: - case DIV_RN_IMM: - case MOD_RN_IMM: - case AND_RN_IMM: - case OR_RN_IMM: - case XOR_RN_IMM: - size = 3; // opcode (1) + register (1) + reg/immediate (1) - break; - case INC_RN: - case DEC_RN: - size = 2; // opcode (1) + register (1) - break; - case INC_ADDR: - case DEC_ADDR: - size = 5; // opcode (1) + 32-bit address (4) - break; - default: - size = 3; - break; - } - } - } else { - // Non-ambiguous instructions that have positive opcodes. - // Use the mapping value (baseOpcode) directly. - switch (baseOpcode) { - case NOP: - case BRK: - case HLT: - size = 1; - break; - case SWAP: - case CMP: - size = 3; - break; - case SWAPN: - case NEG_RN: - case NOT_RN: - size = 2; - break; - case SHL_RN_IMM: - case SHR_RN_IMM: - case SAR_RN_IMM: - size = 3; - break; - case JE: - case JNE: - case JG: - case JL: - case JGE: - case JLE: - case CALL: - size = 5; // opcode (1) + 32-bit address (4)\n break; - case RET: - size = 1; - break; - default: - size = 3; - break; - } - } - addr += size; } - return addr; + +// // Parse the mnemonic and operands. +// char mnemonic[32], operand1[64], operand2[64], operand3[64]; +// operand1[0] = '\0'; +// operand2[0] = '\0'; +// int tokenCount = sscanf(line, "%31s %63[^ ] %63[^ ] %63s", +// mnemonic, operand1, operand2, operand3); +// +// +// // Use the mapper to get a base opcode. +// int baseOpcode = getOpcode(mnemonic); +// if (baseOpcode == -1) { +// printf("Unknown instruction: %s\n", mnemonic); +// continue; +// } +// +// int size = CPU_INSTRUCTION_SIZE; // Instruction size in bytes. +// if (baseOpcode == -2) { +// // MOV instruction requires further resolution. +// int resolvedOpcode = resolveMOV(operand1, operand2); +// if (resolvedOpcode == MOV_RN_IMM || resolvedOpcode == MOV_RN_RM) { +// size = 3; // opcode (1) + reg (1) + immediate or register (1) +// } else if (resolvedOpcode == MOV_RN_ADDR || resolvedOpcode == MOV_ADDR_RN) { +// size = 6; // opcode (1) + one operand as register (1) and one 32-bit address (4) [+ padding if needed] +// } else { +// size = 3; // fallback +// } +// } else if (baseOpcode < 0) { +// // Ambiguous instructions that use resolveALU. +// // For JMP and jump-bit instructions, the jump target is in operand1. +// if (baseOpcode == -11) { +// // JMP: if operand1 starts with '+' or '-', it's relative. +// if (operand1[0] == '+' || operand1[0] == '-') { +// // resolve as JMP_REL. +// int resolvedOpcode = resolveALU(baseOpcode, operand1); +// size = 2; // opcode (1) + 1-byte relative offset (1) +// } else { +// int resolvedOpcode = resolveALU(baseOpcode, operand1); +// size = 5; // opcode (1) + 32-bit absolute address (4) +// } +// } else if (baseOpcode == -14 || baseOpcode == -15) { +// // JMPBS or JMPBC (jump if bit set/clear) +// int resolvedOpcode = resolveALU(baseOpcode, operand1); +// if (operand1[0] == 'R' || operand1[0] == 'r') +// size = 7; // opcode (1) + register (1) + bit (1) + 32-bit jump address (4) +// else +// size = 10; // opcode (1) + 32-bit memory address (4) + bit (1) + 32-bit jump address (4) +// } else { +// // For arithmetic ALU instructions and INC/DEC, +// // use operand2 to resolve. +// int resolvedOpcode = resolveALU(baseOpcode, operand2); +// switch (resolvedOpcode) { +// case ADD_RN_RM: +// case SUB_RN_RM: +// case MUL_RN_RM: +// case DIV_RN_RM: +// case MOD_RN_RM: +// case AND_RN_RM: +// case OR_RN_RM: +// case XOR_RN_RM: +// case ADD_RN_IMM: +// case SUB_RN_IMM: +// case MUL_RN_IMM: +// case DIV_RN_IMM: +// case MOD_RN_IMM: +// case AND_RN_IMM: +// case OR_RN_IMM: +// case XOR_RN_IMM: +// size = 3; // opcode (1) + register (1) + reg/immediate (1) +// break; +// case INC_RN: +// case DEC_RN: +// size = 2; // opcode (1) + register (1) +// break; +// case INC_ADDR: +// case DEC_ADDR: +// size = 5; // opcode (1) + 32-bit address (4) +// break; +// default: +// size = 3; +// break; +// } +// } +// } else { +// // Non-ambiguous instructions that have positive opcodes. +// // Use the mapping value (baseOpcode) directly. +// switch (baseOpcode) { +// case NOP: +// case BRK: +// case HLT: +// size = 1; +// break; +// case SWAP: +// case CMP: +// size = 3; +// break; +// case SWAPN: +// case NEG_RN: +// case NOT_RN: +// size = 2; +// break; +// case SHL_RN_IMM: +// case SHR_RN_IMM: +// case SAR_RN_IMM: +// size = 3; +// break; +// case JE: +// case JNE: +// case JG: +// case JL: +// case JGE: +// case JLE: +// case CALL: +// size = 5; // opcode (1) + 32-bit address (4)\n break; +// case RET: +// size = 1; +// break; +// default: +// size = 3; +// break; +// } +// } +// addr += size; +// } +// return addr; } // // The second pass actually translates the assembly instructions to machine code. // The machine code is written into the provided buffer. (It must be large enough.) // -int 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]; - int addr = 0; + uint32_t addr = 0; const char *ptr = source; + uint32_t lineIndex = 0; + while (*ptr) { ptr = readLine(ptr, line, sizeof(line)); trim(line); - if (line[0] == '\0' || line[0] == ';' || line[0] == '#') + if (line[0] == '\0' || line[0] == ';' || line[0] == '#') { + lineIndex++; continue; + } // Remove any label definitions (up to the colon). char *colon = strchr(line, ':'); if (colon != NULL) { - *colon = ' '; // Replace the colon so the rest of the line can be parsed. + lineIndex++; continue; } if (strlen(line) == 0) @@ -470,11 +488,12 @@ int secondPass(const char *source, uint8_t *code) { // Parse mnemonic and up to three operands. char mnemonic[32], operand1[64], operand2[64], operand3[64]; mnemonic[0] = operand1[0] = operand2[0] = operand3[0] = '\0'; - int tokenCount = sscanf(line, "%31s %63[^, ] %63[^, ] %63s", + int tokenCount = sscanf(line, "%31s %63[^ ] %63[^ ] %63s", mnemonic, operand1, operand2, operand3); // (Optionally, you might trim each operand individually here.) + uint32_t oldAddr = addr; // Map the mnemonic to a base opcode. int baseOpcode = getOpcode(mnemonic); if (baseOpcode == -1) { @@ -489,17 +508,17 @@ int secondPass(const char *source, uint8_t *code) { return 1; } int resolvedOpcode = resolveMOV(operand1, operand2); - code[addr++] = resolvedOpcode; + cpu->memory[addr++] = resolvedOpcode; if (resolvedOpcode == MOV_RN_IMM) { int reg = parseRegister(operand1); uint8_t imm = parseImmediate(operand2); - code[addr++] = reg; - code[addr++] = imm; + cpu->memory[addr++] = reg; + cpu->memory[addr++] = imm; } else if (resolvedOpcode == MOV_RN_RM) { int regDest = parseRegister(operand1); int regSrc = parseRegister(operand2); - code[addr++] = regDest; - code[addr++] = regSrc; + cpu->memory[addr++] = regDest; + cpu->memory[addr++] = regSrc; } else if (resolvedOpcode == MOV_RN_ADDR) { int reg = parseRegister(operand1); // 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); addrStr[strlen(operand2) - 2] = '\0'; uint32_t memAddr = (uint32_t) strtoul(addrStr, NULL, 0); - code[addr++] = reg; - code[addr++] = (memAddr >> 24) & 0xFF; - code[addr++] = (memAddr >> 16) & 0xFF; - code[addr++] = (memAddr >> 8) & 0xFF; - code[addr++] = memAddr & 0xFF; + cpu->memory[addr++] = reg; + cpu->memory[addr++] = memAddr & 0xFF; + cpu->memory[addr++] = (memAddr >> 8) & 0xFF; + cpu->memory[addr++] = (memAddr >> 16) & 0xFF; } else if (resolvedOpcode == MOV_ADDR_RN) { // Destination is memory (written as "[address]"). char addrStr[32]; @@ -519,11 +537,10 @@ int secondPass(const char *source, uint8_t *code) { addrStr[strlen(operand1) - 2] = '\0'; uint32_t memAddr = (uint32_t) strtoul(addrStr, NULL, 0); int reg = parseRegister(operand2); - code[addr++] = (memAddr >> 24) & 0xFF; - code[addr++] = (memAddr >> 16) & 0xFF; - code[addr++] = (memAddr >> 8) & 0xFF; - code[addr++] = memAddr & 0xFF; - code[addr++] = reg; + cpu->memory[addr++] = memAddr & 0xFF; + cpu->memory[addr++] = (memAddr >> 8) & 0xFF; + cpu->memory[addr++] = (memAddr >> 16) & 0xFF; + cpu->memory[addr++] = reg; } } // --- INC and DEC (baseOpcode == -12 or -13) --- @@ -534,20 +551,19 @@ int secondPass(const char *source, uint8_t *code) { return 1; } int resolvedOpcode = resolveALU(baseOpcode, operand1); - code[addr++] = resolvedOpcode; + cpu->memory[addr++] = resolvedOpcode; if (operand1[0] == 'R' || operand1[0] == 'r') { int reg = parseRegister(operand1); - code[addr++] = reg; + cpu->memory[addr++] = reg; } else { // Assume memory reference written as "[address]". char addrStr[32]; strncpy(addrStr, operand1 + 1, strlen(operand1) - 2); addrStr[strlen(operand1) - 2] = '\0'; uint32_t memAddr = (uint32_t) strtoul(addrStr, NULL, 0); - code[addr++] = (memAddr >> 24) & 0xFF; - code[addr++] = (memAddr >> 16) & 0xFF; - code[addr++] = (memAddr >> 8) & 0xFF; - code[addr++] = memAddr & 0xFF; + cpu->memory[addr++] = memAddr & 0xFF; + cpu->memory[addr++] = (memAddr >> 8) & 0xFF; + cpu->memory[addr++] = (memAddr >> 16) & 0xFF; } } // --- Other Ambiguous ALU Instructions (ADD, SUB, MUL, etc.) --- @@ -559,15 +575,15 @@ int secondPass(const char *source, uint8_t *code) { return 1; } int resolvedOpcode = resolveALU(baseOpcode, operand2); - code[addr++] = resolvedOpcode; + cpu->memory[addr++] = resolvedOpcode; int regDest = parseRegister(operand1); - code[addr++] = regDest; + cpu->memory[addr++] = regDest; if (operand2[0] == 'R' || operand2[0] == 'r') { int regSrc = parseRegister(operand2); - code[addr++] = regSrc; + cpu->memory[addr++] = regSrc; } else { uint8_t imm = parseImmediate(operand2); - code[addr++] = imm; + cpu->memory[addr++] = imm; } } // --- JMP Instruction (baseOpcode == -11) --- @@ -577,18 +593,17 @@ int secondPass(const char *source, uint8_t *code) { return 1; } int resolvedOpcode = resolveALU(baseOpcode, operand1); - code[addr++] = resolvedOpcode; + cpu->memory[addr++] = resolvedOpcode; if (operand1[0] == '+' || operand1[0] == '-') { // Relative jump: one-byte offset. uint8_t offset = parseImmediate(operand1); - code[addr++] = offset; + cpu->memory[addr++] = offset; } else { // Absolute jump: use label lookup for 32-bit address. uint32_t jumpAddr = (uint32_t) lookupLabel(operand1); - code[addr++] = (jumpAddr >> 24) & 0xFF; - code[addr++] = (jumpAddr >> 16) & 0xFF; - code[addr++] = (jumpAddr >> 8) & 0xFF; - code[addr++] = jumpAddr & 0xFF; + cpu->memory[addr++] = jumpAddr & 0xFF; + cpu->memory[addr++] = (jumpAddr >> 8) & 0xFF; + cpu->memory[addr++] = (jumpAddr >> 16) & 0xFF; } } // --- Jump Bit Set/Clear Instructions (JMPBS, JMPBC) --- @@ -598,33 +613,31 @@ int secondPass(const char *source, uint8_t *code) { return 1; } int resolvedOpcode = resolveALU(baseOpcode, operand1); - code[addr++] = resolvedOpcode; + cpu->memory[addr++] = resolvedOpcode; // Encode the source operand (register or memory). if (operand1[0] == 'R' || operand1[0] == 'r') { int reg = parseRegister(operand1); - code[addr++] = reg; + cpu->memory[addr++] = reg; } else { char addrStr[32]; strncpy(addrStr, operand1 + 1, strlen(operand1) - 2); addrStr[strlen(operand1) - 2] = '\0'; uint32_t memAddr = (uint32_t) strtoul(addrStr, NULL, 0); - code[addr++] = (memAddr >> 24) & 0xFF; - code[addr++] = (memAddr >> 16) & 0xFF; - code[addr++] = (memAddr >> 8) & 0xFF; - code[addr++] = memAddr & 0xFF; + cpu->memory[addr++] = memAddr & 0xFF; + cpu->memory[addr++] = (memAddr >> 8) & 0xFF; + cpu->memory[addr++] = (memAddr >> 16) & 0xFF; } // Encode the bit number (a one-byte immediate). uint8_t bitVal = parseImmediate(operand2); - code[addr++] = bitVal; + cpu->memory[addr++] = bitVal; // Encode the jump target (label -> 32-bit address). uint32_t jumpAddr = (uint32_t) lookupLabel(operand3); - code[addr++] = (jumpAddr >> 24) & 0xFF; - code[addr++] = (jumpAddr >> 16) & 0xFF; - code[addr++] = (jumpAddr >> 8) & 0xFF; - code[addr++] = jumpAddr & 0xFF; + cpu->memory[addr++] = jumpAddr & 0xFF; + cpu->memory[addr++] = (jumpAddr >> 8) & 0xFF; + cpu->memory[addr++] = (jumpAddr >> 16) & 0xFF; } // --- Non-ambiguous Instructions --- - else if (baseOpcode > 0) { + else if (baseOpcode >= 0) { switch (baseOpcode) { case CMP: case SWAP: { @@ -632,11 +645,11 @@ int secondPass(const char *source, uint8_t *code) { fprintf(stderr, "Error: %s requires two operands.\n", mnemonic); return 1; } - code[addr++] = baseOpcode; + cpu->memory[addr++] = baseOpcode; int r1 = parseRegister(operand1); int r2 = parseRegister(operand2); - code[addr++] = r1; - code[addr++] = r2; + cpu->memory[addr++] = r1; + cpu->memory[addr++] = r2; break; } case SWAPN: @@ -646,9 +659,9 @@ int secondPass(const char *source, uint8_t *code) { fprintf(stderr, "Error: %s requires one operand.\n", mnemonic); return 1; } - code[addr++] = baseOpcode; + cpu->memory[addr++] = baseOpcode; int reg = parseRegister(operand1); - code[addr++] = reg; + cpu->memory[addr++] = reg; break; } 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); return 1; } - code[addr++] = baseOpcode; + cpu->memory[addr++] = baseOpcode; int reg = parseRegister(operand1); - code[addr++] = reg; + cpu->memory[addr++] = reg; uint8_t imm = parseImmediate(operand2); - code[addr++] = imm; + cpu->memory[addr++] = imm; break; } case JE: @@ -676,7 +689,7 @@ int secondPass(const char *source, uint8_t *code) { fprintf(stderr, "Error: %s requires one operand.\n", mnemonic); return 1; } - code[addr++] = baseOpcode; + cpu->memory[addr++] = baseOpcode; // If the operand isn’t purely numeric, treat it as a label. if (!isdigit(operand1[0])) { int labelAddr = lookupLabel(operand1); @@ -684,16 +697,14 @@ int secondPass(const char *source, uint8_t *code) { fprintf(stderr, "Error: undefined label '%s'\n", operand1); return 1; } - code[addr++] = (labelAddr >> 24) & 0xFF; - code[addr++] = (labelAddr >> 16) & 0xFF; - code[addr++] = (labelAddr >> 8) & 0xFF; - code[addr++] = labelAddr & 0xFF; + cpu->memory[addr++] = labelAddr & 0xFF; + cpu->memory[addr++] = (labelAddr >> 8) & 0xFF; + cpu->memory[addr++] = (labelAddr >> 16) & 0xFF; } else { uint32_t immAddr = (uint32_t) strtoul(operand1, NULL, 0); - code[addr++] = (immAddr >> 24) & 0xFF; - code[addr++] = (immAddr >> 16) & 0xFF; - code[addr++] = (immAddr >> 8) & 0xFF; - code[addr++] = immAddr & 0xFF; + cpu->memory[addr++] = immAddr & 0xFF; + cpu->memory[addr++] = (immAddr >> 8) & 0xFF; + cpu->memory[addr++] = (immAddr >> 16) & 0xFF; } break; } @@ -701,7 +712,7 @@ int secondPass(const char *source, uint8_t *code) { case BRK: case HLT: case NOP: { - code[addr++] = baseOpcode; + cpu->memory[addr++] = baseOpcode; break; } default: { @@ -713,17 +724,14 @@ int secondPass(const char *source, uint8_t *code) { fprintf(stderr, "Error: Unknown instruction '%s'\n", mnemonic); 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; -} - - -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); } \ No newline at end of file diff --git a/assembler/assembler.h b/assembler/assembler.h index d2c79a4..073143d 100644 --- a/assembler/assembler.h +++ b/assembler/assembler.h @@ -77,15 +77,13 @@ int resolveALU(int baseOpcode, const char *src); // 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). // -int firstPass(const char *source); +void firstPass(const char *source); // // The second pass actually translates the assembly instructions to machine code. // The machine code is written into the provided buffer. (It must be large enough.) // -int secondPass(const char *source, uint8_t *code); - -void completePass(const char *input, CPU *cpu, bool erase); +int completePass(const char *input, CPU *cpu, bool erase); #endif //RISCB_ASSEMBLER_H diff --git a/cpu/core.c b/cpu/core.c index 713d87b..db65cb7 100644 --- a/cpu/core.c +++ b/cpu/core.c @@ -34,11 +34,22 @@ void step(CPU *cpu) { cpu->mode |= CPU_MODE_HALTED; } } - uint8_t opcode = read_mem(cpu, cpu->pc++); uint8_t reg1, reg2, imm, temp, temp2; - uint32_t newPC, addrTemp; + uint32_t newPC, addrTemp, oldPC; 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) { case NOP: //Don't do anything @@ -491,5 +502,12 @@ void step(CPU *cpu) { printf("Unknown opcode: %d\n", opcode); 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++; } \ No newline at end of file diff --git a/cpu/core.h b/cpu/core.h index 397dc35..ffe39c9 100644 --- a/cpu/core.h +++ b/cpu/core.h @@ -23,13 +23,16 @@ #define CPU_MODE_STEP (1 << 4) #define CPU_MODE_SECOND (1 << 5) +#define CPU_INSTRUCTION_SIZE 8 //Biggest instruction + // CPU state typedef struct { uint8_t regs[REG_COUNT]; uint8_t memory[MEM_SIZE]; - uint32_t pc; // Program counter 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 uint8_t flags; // Status flags uint8_t mode; diff --git a/cpu/memory.c b/cpu/memory.c index 6a11c60..06d8ef2 100644 --- a/cpu/memory.c +++ b/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); } +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 out = read_mem32(cpu, cpu->pc); - cpu->pc += 4; + uint32_t out = read_mem24(cpu, cpu->pc); + cpu->pc += 3; if (out >= MEM_SIZE) { out = MEM_SIZE - 1; } @@ -58,8 +62,7 @@ void write_stack(CPU *cpu) { for (uint32_t reg = 0; reg < REG_COUNT; reg += 4) { uint32_t packed = cpu->regs[reg] | ((reg + 1 < REG_COUNT) ? (cpu->regs[reg + 1] << 8) : 0) | - ((reg + 2 < REG_COUNT) ? (cpu->regs[reg + 2] << 16) : 0) | - ((reg + 3 < REG_COUNT) ? (cpu->regs[reg + 3] << 24) : 0); + ((reg + 2 < REG_COUNT) ? (cpu->regs[reg + 2] << 16) : 0); cpu->stack[++cpu->stack_ptr] = packed; } cpu->stack[++cpu->stack_ptr] = cpu->flags; @@ -83,7 +86,6 @@ void read_stack(CPU *cpu) { cpu->regs[reg] = (packed & 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 - 3 >= 0) cpu->regs[reg - 3] = ((packed >> 24) & 0xFF); } // Restore PC diff --git a/docs/examples/fulltest.bsm b/docs/examples/fulltest.bsm new file mode 100644 index 0000000..5f054eb --- /dev/null +++ b/docs/examples/fulltest.bsm @@ -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 diff --git a/docs/examples/jmptest.bsm b/docs/examples/jmptest.bsm new file mode 100644 index 0000000..2706ec5 --- /dev/null +++ b/docs/examples/jmptest.bsm @@ -0,0 +1,6 @@ +TEST: +INC R1 +INC R2 +MOV R2 [20] +JMP TEST +HLT diff --git a/docs/examples/test1.bsm b/docs/examples/test1.bsm new file mode 100644 index 0000000..ff4a51a --- /dev/null +++ b/docs/examples/test1.bsm @@ -0,0 +1,4 @@ +INC R1 +BRK +INC R2 +HLT \ No newline at end of file diff --git a/docs/instructions.md b/docs/instructions.md new file mode 100644 index 0000000..2fd4d64 --- /dev/null +++ b/docs/instructions.md @@ -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**. \ No newline at end of file diff --git a/main.c b/main.c index 4e8f000..9611e1b 100644 --- a/main.c +++ b/main.c @@ -72,24 +72,26 @@ char *read_file_as_string(const char *filename) { return buffer; // Caller must free the memory } -void updateState() { - cpuStatsTexture = renderVals(&cpu, &smallFont, &smallerFont, renderer); - cpuStateTexture = renderState(&cpu, &biggerFont, renderer); - char *dump = hexdump_to_string(cpu.memory, sizeof(cpu.memory)); - fill_editor_from_string(&memoryViewer, dump, renderer); +void updateState(bool full) { + renderVals(&cpu, &smallFont, &smallerFont, renderer, &cpuStatsTexture); + renderState(&cpu, &biggerFont, renderer, &cpuStateTexture); + char *dump = hexdump_to_string(cpu.memory, full ? 0 : memoryViewer.cursor_line_offset * 16, + 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); } void compile(bool erase) { generate_string(&codeEditor); completePass(codeEditor.outputString, &cpu, erase); - updateState(); + updateState(true); } int init() { //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()); return 1; } @@ -108,17 +110,21 @@ int init() { return 1; } //Get window surface - renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE); + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); if (renderer == NULL) { printf("Renderer could not be created SDL_Error: %s\n", SDL_GetError()); 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); smallFont = prepText(renderer, 12, "../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(&memoryViewer, &smallerFont, 550, 80, renderer, 80, MEM_SIZE / 16 + 2, 70, true); + init_editor(&codeEditor, &smallFont, 10, 80, renderer, 54, 1000, 48, false); + init_editor(&memoryViewer, &smallerFont, 738, 80, renderer, 59, MEM_SIZE / 16 + 2, 70, true); SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT); SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, NULL); for (int i = 0; i < editorCount; i++) { @@ -135,7 +141,7 @@ int render() { SDL_RenderClear(renderer); 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; @@ -146,7 +152,6 @@ int render() { SDL_QueryTexture(cpuStatsTexture, NULL, NULL, &rect2.w, &rect2.h); - SDL_RenderCopy(renderer, cpuStatsTexture, NULL, &rect2); rect2.x = 100; @@ -156,7 +161,6 @@ int render() { SDL_QueryTexture(cpuStateTexture, NULL, NULL, &rect2.w, &rect2.h); - SDL_RenderCopy(renderer, cpuStateTexture, NULL, &rect2); SDL_RenderPresent(renderer); @@ -292,43 +296,54 @@ int processEvent(SDL_Event e) { int keySym = ConvertKPToNonKP(e.key.keysym.sym); int keyMod = e.key.keysym.mod; cursor = true; + bool moved = false; switch (keySym) { case SDLK_UP: move_cursor_relative(&activeEditor, -1, 0, false, renderer); + moved = true; break; 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; case SDLK_DOWN: move_cursor_relative(&activeEditor, 1, 0, false, renderer); + moved = true; break; 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; case SDLK_LEFT: move_cursor_relative(&activeEditor, 0, -1, false, renderer); + moved = true; break; case SDLK_HOME: if (keyMod & KMOD_CTRL) { move_cursor(&activeEditor, 0, 0, false, renderer); + moved = true; break; } move_cursor(&activeEditor, activeEditor.cursor_line, 0, false, renderer); + moved = true; break; case SDLK_RIGHT: move_cursor_relative(&activeEditor, 0, 1, false, renderer); + moved = true; break; case SDLK_END: int lineLen = strlen(activeEditor.lines[activeEditor.cursor_line].text); 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; } move_cursor(&activeEditor, activeEditor.cursor_line, lineLen, false, renderer); + moved = true; break; case SDLK_F9: cpu.mode ^= CPU_MODE_LOOP; - updateState(); + updateState(false); return 1; case SDLK_F8: if (++cpuSpeedTemp == 3) { @@ -336,7 +351,7 @@ int processEvent(SDL_Event e) { } cpu.mode &= ~(CPU_MODE_SECOND | CPU_MODE_STEP); cpu.mode |= cpuSpeedTemp << 4; - updateState(); + updateState(false); return 1; case SDLK_F5: compile(!(keyMod & KMOD_CTRL)); @@ -345,7 +360,7 @@ int processEvent(SDL_Event e) { cpu.pc = 0; } cpu.mode &= ~(CPU_MODE_HALTED | CPU_MODE_PAUSED | CPU_MODE_ERROR); - updateState(); + updateState(false); break; case SDLK_ESCAPE: @@ -353,7 +368,7 @@ int processEvent(SDL_Event e) { if (keyMod & (KMOD_CTRL | KMOD_SHIFT)) { cpu.mode |= CPU_MODE_HALTED; } - updateState(); + updateState(false); break; case SDLK_s: @@ -373,26 +388,30 @@ int processEvent(SDL_Event e) { if (keyMod & KMOD_CTRL) { FILE *fptr; char fname[20]; - sscanf(editors[0].lines[0].text, "%s", fname); + sscanf(editors[0].lines[editors[0].cursor_line].text, "%s", fname); toLowerCase(fname); strcat(fname, ".bsm"); fptr = fopen(fname, "r"); - char *prog = read_file_as_string(fname); - fill_editor_from_string(&editors[0], prog, renderer); - free(prog); - fputs(editors[0].outputString, fptr); - fclose(fptr); + if (fptr) { + char *prog = read_file_as_string(fname); + toUpperCase(prog); + fill_editor_from_string(&editors[0], prog, 0, true, renderer); + free(prog); + fclose(fptr); + } return 1; } break; case SDLK_BACKSPACE: if (!activeEditor.readOnly) { remove_character(&activeEditor, false, renderer); + moved = true; } break; case SDLK_DELETE: if (!activeEditor.readOnly) { remove_character(&activeEditor, true, renderer); + moved = true; } break; case SDLK_RETURN: @@ -403,6 +422,7 @@ int processEvent(SDL_Event e) { } if (!activeEditor.readOnly) { insert_line_rel(&activeEditor, renderer); + moved = true; } break; case SDLK_TAB: @@ -415,6 +435,9 @@ int processEvent(SDL_Event e) { default: break; } + if (moved && &activeEditor == &memoryViewer) { + updateState(false); + } } else if (e.type == SDL_TEXTINPUT) { for (int i = 0; e.text.text[i] != '\0'; i++) { // Iterate over the input string 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_SECOND) { - if (frames % 60) { + if (!(frames % 60)) { step(&cpu); - updateState(); + updateState(false); } } else { step(&cpu); - updateState(); + updateState(false); } if (cpu.mode & CPU_MODE_STEP) { cpu.mode |= CPU_MODE_PAUSED; - updateState(); + updateState(false); } } end = SDL_GetTicks64(); @@ -477,7 +500,7 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[]) if (timeNeeded < delayNeeded) { SDL_Delay(delayNeeded - timeNeeded); } 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]); } + puts(SDL_GetError()); + + //SDL_DestroyRenderer(renderer); + //Destroy window - SDL_DestroyWindow(window); + //SDL_DestroyWindow(window); //Quit SDL subsystems - SDL_Quit(); + //SDL_Quit(); return 0; } \ No newline at end of file diff --git a/util/cpustatusui.c b/util/cpustatusui.c index cf25877..d9fbcbb 100644 --- a/util/cpustatusui.c +++ b/util/cpustatusui.c @@ -6,8 +6,8 @@ #include "cpustatusui.h" #include "font.h" -SDL_Texture *renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont, - SDL_Renderer *renderer) { +void renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont, + SDL_Renderer *renderer, SDL_Texture **out) { CPUStatusPart *stats = NULL; int statsCount = 0; @@ -16,12 +16,14 @@ SDL_Texture *renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont, getStats(cpu, &stats, &statsCount); 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); - SDL_Texture *out = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, - oneFieldW * statsCount, oneFieldH); + if (!*out) { + *out = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, + oneFieldW * statsCount, oneFieldH); + } - SDL_SetRenderTarget(renderer, out); + SDL_SetRenderTarget(renderer, *out); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); @@ -61,7 +63,7 @@ SDL_Texture *renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont, } SDL_SetRenderTarget(renderer, NULL); - return out; + free(stats); } void getStats(CPU *cpu, CPUStatusPart **cpuStatus, int *cpuStatusCount) { @@ -81,27 +83,27 @@ void getStats(CPU *cpu, CPUStatusPart **cpuStatus, int *cpuStatusCount) { 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; 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; index++; - strncpy((*cpuStatus)[index].name, "FLG", sizeof((*cpuStatus)[index].name)); + strncpy((*cpuStatus)[index].name, "FLAG", sizeof((*cpuStatus)[index].name)); (*cpuStatus)[index].value = cpu->flags; index++; - strncpy((*cpuStatus)[index].name, "MOD", sizeof((*cpuStatus)[index].name)); + strncpy((*cpuStatus)[index].name, "MODE", sizeof((*cpuStatus)[index].name)); (*cpuStatus)[index].value = cpu->mode; index++; - strncpy((*cpuStatus)[index].name, "CYC", sizeof((*cpuStatus)[index].name)); + strncpy((*cpuStatus)[index].name, "CYCL", sizeof((*cpuStatus)[index].name)); (*cpuStatus)[index].value = cpu->cycle; 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); (*cpuStatus)[index].value = cpu->regs[i]; index++; @@ -110,7 +112,7 @@ void getStats(CPU *cpu, CPUStatusPart **cpuStatus, int *cpuStatusCount) { *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 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 allFieldW = oneFieldW * strlen(valueStr); const int oneFieldH = (titleFont->size + 1); - SDL_Texture *out = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, - allFieldW, oneFieldH); + if (!*out) { + *out = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, + allFieldW, oneFieldH); + } - SDL_SetRenderTarget(renderer, out); + SDL_SetRenderTarget(renderer, *out); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_RenderClear(renderer); @@ -164,5 +168,4 @@ SDL_Texture *renderState(CPU *cpu, BitmapFont *titleFont, SDL_Renderer *renderer } SDL_SetRenderTarget(renderer, NULL); - return out; } \ No newline at end of file diff --git a/util/cpustatusui.h b/util/cpustatusui.h index fc4502e..4194123 100644 --- a/util/cpustatusui.h +++ b/util/cpustatusui.h @@ -9,14 +9,14 @@ #include "../cpu/core.h" typedef struct { - char name[4]; + char name[5]; uint32_t value; } CPUStatusPart; -SDL_Texture *renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont, - SDL_Renderer *renderer); +void renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont, + 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); diff --git a/util/font.c b/util/font.c index 9b52efa..4f8d377 100644 --- a/util/font.c +++ b/util/font.c @@ -12,8 +12,12 @@ prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file, uint8_t out.color = (SDL_Color) {r, g, b, a}; unsigned int i = 1; 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}; out.surface[i] = TTF_RenderText_Solid(gFont, tmpOut, out.color); + } out.texture[i] = SDL_CreateTextureFromSurface(renderer, out.surface[i]); i++; } while (i < 256); diff --git a/util/hexdump.c b/util/hexdump.c index 223d32f..33d5b37 100644 --- a/util/hexdump.c +++ b/util/hexdump.c @@ -6,44 +6,39 @@ #include #include #include +#include +#include #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 - 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 char *output = malloc(estimated_size); 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) { - offset += snprintf(output + offset, estimated_size - offset, "%08zx ", i); + for (uint32_t i = start; i < end; i += BYTES_PER_LINE) { + // Print offset + out_offset += snprintf(output + out_offset, estimated_size - out_offset, "%07x ", i); // Print hex values - for (size_t j = 0; j < BYTES_PER_LINE; j++) { - if (i + j < size) - offset += snprintf(output + offset, estimated_size - offset, "%02x ", data[i + j]); + for (uint32_t j = 0; j < BYTES_PER_LINE; j++) { + if (i + j < end) + out_offset += snprintf(output + out_offset, estimated_size - out_offset, "%02x ", data[i + j]); else - offset += snprintf(output + offset, estimated_size - offset, " "); // Padding - if (j == 7) offset += snprintf(output + offset, estimated_size - offset, " "); // Extra space + out_offset += snprintf(output + out_offset, estimated_size - out_offset, " "); // Padding + if (j == 7) + out_offset += snprintf(output + out_offset, estimated_size - out_offset, " "); // Extra space } - offset += snprintf(output + offset, estimated_size - offset, " |"); - - // 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"); + out_offset += snprintf(output + out_offset, estimated_size - out_offset, "\n"); } return output; diff --git a/util/hexdump.h b/util/hexdump.h index 9a948b8..4e3abb3 100644 --- a/util/hexdump.h +++ b/util/hexdump.h @@ -6,7 +6,8 @@ #define RISCB_HEXDUMP_H #include +#include -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 diff --git a/util/texteditor.c b/util/texteditor.c index 89efcc1..6b45193 100644 --- a/util/texteditor.c +++ b/util/texteditor.c @@ -5,13 +5,14 @@ #include "texteditor.h" #include "font.h" +#include "../cpu/core.h" // Initialize the text editor with dynamic sizes. 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) { editor->max_line_width = max_line_width; - editor->max_lines_asm = max_lines_asm; - editor->max_lines_display = max_lines_display; + editor->maxLines = max_lines_asm; + editor->displayLineCount = max_lines_display; editor->line_count = 0; editor->cursor_line = 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->cursorRect = 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->cursorRect, 0, sizeof(SDL_Rect)); memset(editor->rect, 0, sizeof(SDL_Rect)); + memset(editor->highlightedLineRect, 0, sizeof(SDL_Rect)); // 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) { fprintf(stderr, "Failed to allocate memory for lines.\n"); exit(EXIT_FAILURE); } // 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)); if (!editor->lines[i].text) { 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. - editor->outputString = (char *) malloc(sizeof(char) * (editor->max_line_width * editor->max_lines_asm + 1)); - editor->displayString = (char *) malloc(sizeof(char) * (editor->max_line_width * editor->max_lines_display + 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->displayLineCount + 1)); if (!editor->outputString || !editor->displayString) { fprintf(stderr, "Failed to allocate memory for output/display strings.\n"); 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->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->y = 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->h = editor->rect->h; editor->outRect->x = x; 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->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; // 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) { - 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"); 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) { - 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; } @@ -154,11 +170,27 @@ void remove_character(TextEditor *editor, bool isDelete, SDL_Renderer *renderer) for (int i = editor->cursor_pos; i < len; i++) { 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 { // Backspace behavior (delete character before cursor) - if (editor->cursor_pos == 0 && editor->line_count > 1) { - // Merge with the previous line + if (editor->cursor_pos == 0 && editor->cursor_line > 0) { + // 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++) { strcpy(editor->lines[i].text, editor->lines[i + 1].text); 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].active = 0; editor->line_count--; - if (editor->cursor_line >= editor->line_count) { - editor->cursor_line = editor->line_count - 1; - } - editor->cursor_pos = strlen(editor->lines[editor->cursor_line].text); + + // Move cursor to the end of the previous line + editor->cursor_line--; + editor->cursor_pos = prev_len; } else if (editor->cursor_pos > 0) { for (int i = editor->cursor_pos - 1; i < len; i++) { 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) { 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) { 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) { editor->cursor_line_offset = new_line; } - if (new_line >= editor->cursor_line_offset + editor->max_lines_display) { - editor->cursor_line_offset = new_line - editor->max_lines_display + 1; + if (new_line >= editor->cursor_line_offset + editor->displayLineCount) { + 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); @@ -219,7 +265,7 @@ void generate_string_display(TextEditor *editor, SDL_Renderer *renderer) { 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) end_line = editor->line_count; @@ -227,7 +273,7 @@ void generate_string_display(TextEditor *editor, SDL_Renderer *renderer) { editor->displayString[0] = '\0'; SDL_SetRenderTarget(renderer, editor->texture); - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_RenderClear(renderer); SDL_Rect charDstRect; @@ -263,7 +309,8 @@ void generate_string_display(TextEditor *editor, SDL_Renderer *renderer) { 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) { SDL_Rect bgRect; bgRect = *editor->outRect; @@ -271,20 +318,57 @@ void editor_render(TextEditor *editor, SDL_Renderer *renderer, bool isActive, bo bgRect.y -= 6; bgRect.w += 12; bgRect.h += 12; + + SDL_SetRenderDrawColor(renderer, editor->readOnly ? 128 : 0, editor->readOnly ? 0 : 128, 64, 255); 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) { - SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255); - SDL_RenderFillRect(renderer, editor->cursorRect); + SDL_SetRenderDrawColor(renderer, + 0, 255, 255, 128); + SDL_RenderFillRect(renderer, editor + ->cursorRect); + } } void generate_string(TextEditor *editor) { 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 (strlen(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) { printf("Invalid editor or content pointer!\n"); return; } + char *str = content; + + int numLines = 0; + while (*str) if (*str++ == '\n') ++numLines; + // 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].active = 0; } - editor->line_count = 0; - editor->cursor_line = 0; - editor->cursor_pos = 0; + if (isComplete) { + editor->line_count = numLines; + if (editor->line_count >= editor->maxLines) { + editor->line_count = editor->maxLines - 1; + } + } // Parse the content and fill the editor lines 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; // 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++; } @@ -328,9 +421,11 @@ void fill_editor_from_string(TextEditor *editor, const char *content, SDL_Render // Move past the newline character if present if (*ptr == '\n') ptr++; } + editor->lines[line_index].active = 1; // 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_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. void destroy_editor(TextEditor *editor) { 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); } - free(editor->outputString); - free(editor->displayString); + //free(editor->outputString); + //free(editor->displayString); free(editor->outRect); free(editor->rect); diff --git a/util/texteditor.h b/util/texteditor.h index 22d21c7..6e475c4 100644 --- a/util/texteditor.h +++ b/util/texteditor.h @@ -13,6 +13,7 @@ #include #include #include "font.h" +#include "../cpu/core.h" typedef struct { char *text; // Dynamically allocated string for this line @@ -22,25 +23,26 @@ typedef struct { typedef struct { Line *lines; // Dynamic array of 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_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_offset; // Display offset (first line in the display) int cursor_pos; // Current cursor position in line - char *outputString; // Dynamically allocated output string (size: max_line_width * max_lines_asm + 1) - char *displayString; // Dynamically allocated display string (size: max_line_width * max_lines_display + 1) + char *outputString; // Dynamically allocated output string (size: max_line_width * maxLines + 1) + char *displayString; // Dynamically allocated display string (size: max_line_width * displayLineCount + 1) SDL_Rect *rect; SDL_Rect *outRect; SDL_Texture *texture; bool readOnly; BitmapFont *font; SDL_Rect *cursorRect; + SDL_Rect *highlightedLineRect; } 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. 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); @@ -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 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); @@ -64,7 +66,8 @@ void generate_string_display(TextEditor *editor, SDL_Renderer *renderer); 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. void destroy_editor(TextEditor *editor);