Something is almost working
This commit is contained in:
@@ -16,6 +16,10 @@ add_executable(RISCB main.c
|
|||||||
cpu/core.c
|
cpu/core.c
|
||||||
cpu/core.h
|
cpu/core.h
|
||||||
util/texteditor.c
|
util/texteditor.c
|
||||||
util/texteditor.h) # Ensure the target is defined before linking
|
util/texteditor.h
|
||||||
|
util/hexdump.c
|
||||||
|
util/hexdump.h
|
||||||
|
util/cpustatusui.c
|
||||||
|
util/cpustatusui.h) # Ensure the target is defined before linking
|
||||||
|
|
||||||
target_link_libraries(RISCB SDL2 SDL2_ttf m)
|
target_link_libraries(RISCB SDL2 SDL2_ttf m)
|
||||||
|
@@ -32,10 +32,10 @@ int lookupLabel(const char *name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add a label to the table
|
// Add a label to the table
|
||||||
void addLabel(const char *name, int address) {
|
int addLabel(const char *name, int address) {
|
||||||
if (labelCount >= MAX_LABELS) {
|
if (labelCount >= MAX_LABELS) {
|
||||||
fprintf(stderr, "Too many labels!\n");
|
fprintf(stderr, "Too many labels!\n");
|
||||||
exit(1);
|
return 1;
|
||||||
}
|
}
|
||||||
strncpy(labels[labelCount].name, name, sizeof(labels[labelCount].name));
|
strncpy(labels[labelCount].name, name, sizeof(labels[labelCount].name));
|
||||||
labels[labelCount].address = address;
|
labels[labelCount].address = address;
|
||||||
@@ -90,6 +90,16 @@ void toUpperCase(char *string) {
|
|||||||
if (*string > 0x60 && *string < 0x7b) {
|
if (*string > 0x60 && *string < 0x7b) {
|
||||||
(*string) -= 0x20;
|
(*string) -= 0x20;
|
||||||
}
|
}
|
||||||
|
string++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void toLowerCase(char *string) {
|
||||||
|
while (*string) {
|
||||||
|
if (*string >= 'A' && *string <= 'Z') {
|
||||||
|
(*string) += 0x20;
|
||||||
|
}
|
||||||
|
string++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +114,8 @@ int getOpcode(char *mnemonic) {
|
|||||||
return NOP;
|
return NOP;
|
||||||
else if (strcmp(mnemonic, "BRK") == 0)
|
else if (strcmp(mnemonic, "BRK") == 0)
|
||||||
return BRK;
|
return BRK;
|
||||||
|
else if (strcmp(mnemonic, "HLT") == 0)
|
||||||
|
return HLT;
|
||||||
else if (strcmp(mnemonic, "MOV") == 0)
|
else if (strcmp(mnemonic, "MOV") == 0)
|
||||||
return -2; // Special case: we must decide between MOV_RN_IMM, MOV_RN_RM, MOV_RN_ADDR, MOV_ADDR_RN
|
return -2; // Special case: we must decide between MOV_RN_IMM, MOV_RN_RM, MOV_RN_ADDR, MOV_ADDR_RN
|
||||||
else if (strcmp(mnemonic, "SWAP") == 0)
|
else if (strcmp(mnemonic, "SWAP") == 0)
|
||||||
@@ -281,6 +293,7 @@ const char *readLine(const char *source, char *buffer, size_t maxLen) {
|
|||||||
int firstPass(const char *source) {
|
int firstPass(const char *source) {
|
||||||
char line[MAX_LINE_LENGTH];
|
char line[MAX_LINE_LENGTH];
|
||||||
int addr = 0;
|
int addr = 0;
|
||||||
|
labelCount = 0;
|
||||||
const char *ptr = source;
|
const char *ptr = source;
|
||||||
|
|
||||||
while (*ptr) {
|
while (*ptr) {
|
||||||
@@ -305,10 +318,12 @@ int firstPass(const char *source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse the mnemonic and operands.
|
// Parse the mnemonic and operands.
|
||||||
char mnemonic[32], operand1[64], operand2[64];
|
char mnemonic[32], operand1[64], operand2[64], operand3[64];
|
||||||
operand1[0] = '\0';
|
operand1[0] = '\0';
|
||||||
operand2[0] = '\0';
|
operand2[0] = '\0';
|
||||||
sscanf(line, "%31s %63[^,], %63s", mnemonic, operand1, operand2);
|
int tokenCount = sscanf(line, "%31s %63[^, ] %63[^, ] %63s",
|
||||||
|
mnemonic, operand1, operand2, operand3);
|
||||||
|
|
||||||
|
|
||||||
// Use the mapper to get a base opcode.
|
// Use the mapper to get a base opcode.
|
||||||
int baseOpcode = getOpcode(mnemonic);
|
int baseOpcode = getOpcode(mnemonic);
|
||||||
@@ -390,6 +405,7 @@ int firstPass(const char *source) {
|
|||||||
switch (baseOpcode) {
|
switch (baseOpcode) {
|
||||||
case NOP:
|
case NOP:
|
||||||
case BRK:
|
case BRK:
|
||||||
|
case HLT:
|
||||||
size = 1;
|
size = 1;
|
||||||
break;
|
break;
|
||||||
case SWAP:
|
case SWAP:
|
||||||
@@ -439,57 +455,57 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
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] == '#')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Process labels: replace colon with a space.
|
// Remove any label definitions (up to the colon).
|
||||||
char *colon = strchr(line, ':');
|
char *colon = strchr(line, ':');
|
||||||
if (colon != NULL) {
|
if (colon != NULL) {
|
||||||
*colon = ' ';
|
*colon = ' '; // Replace the colon so the rest of the line can be parsed.
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (strlen(line) == 0)
|
if (strlen(line) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Parse the mnemonic and operands.
|
// Parse mnemonic and up to three operands.
|
||||||
char mnemonic[32], operand1[64], operand2[64];
|
char mnemonic[32], operand1[64], operand2[64], operand3[64];
|
||||||
operand1[0] = '\0';
|
mnemonic[0] = operand1[0] = operand2[0] = operand3[0] = '\0';
|
||||||
operand2[0] = '\0';
|
int tokenCount = sscanf(line, "%31s %63[^, ] %63[^, ] %63s",
|
||||||
sscanf(line, "%31s %63[^,], %63s", mnemonic, operand1, operand2);
|
mnemonic, operand1, operand2, operand3);
|
||||||
|
|
||||||
// Use the mapper to get the base opcode.
|
// (Optionally, you might trim each operand individually here.)
|
||||||
|
|
||||||
|
// Map the mnemonic to a base opcode.
|
||||||
int baseOpcode = getOpcode(mnemonic);
|
int baseOpcode = getOpcode(mnemonic);
|
||||||
if (baseOpcode == -1) {
|
if (baseOpcode == -1) {
|
||||||
fprintf(stderr, "Unknown instruction: %s\n", mnemonic);
|
fprintf(stderr, "Unknown instruction: %s\n", mnemonic);
|
||||||
exit(1);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- MOV Instruction ---
|
// --- MOV Instruction (baseOpcode == -2) ---
|
||||||
if (baseOpcode == -2) { // MOV is ambiguous.
|
if (baseOpcode == -2) {
|
||||||
char *dest = strtok(NULL, " ,");
|
if (strlen(operand1) == 0 || strlen(operand2) == 0) {
|
||||||
char *src = strtok(NULL, " ,");
|
|
||||||
if (!dest || !src) {
|
|
||||||
fprintf(stderr, "Error: MOV requires two operands.\n");
|
fprintf(stderr, "Error: MOV requires two operands.\n");
|
||||||
exit(1);
|
return 1;
|
||||||
}
|
}
|
||||||
int resolvedOpcode = resolveMOV(dest, src);
|
int resolvedOpcode = resolveMOV(operand1, operand2);
|
||||||
code[addr++] = resolvedOpcode;
|
code[addr++] = resolvedOpcode;
|
||||||
if (resolvedOpcode == MOV_RN_IMM) {
|
if (resolvedOpcode == MOV_RN_IMM) {
|
||||||
int reg = parseRegister(dest);
|
int reg = parseRegister(operand1);
|
||||||
uint8_t imm = parseImmediate(src);
|
uint8_t imm = parseImmediate(operand2);
|
||||||
code[addr++] = reg;
|
code[addr++] = reg;
|
||||||
code[addr++] = imm;
|
code[addr++] = imm;
|
||||||
} else if (resolvedOpcode == MOV_RN_RM) {
|
} else if (resolvedOpcode == MOV_RN_RM) {
|
||||||
int regDest = parseRegister(dest);
|
int regDest = parseRegister(operand1);
|
||||||
int regSrc = parseRegister(src);
|
int regSrc = parseRegister(operand2);
|
||||||
code[addr++] = regDest;
|
code[addr++] = regDest;
|
||||||
code[addr++] = regSrc;
|
code[addr++] = regSrc;
|
||||||
} else if (resolvedOpcode == MOV_RN_ADDR) {
|
} else if (resolvedOpcode == MOV_RN_ADDR) {
|
||||||
int reg = parseRegister(dest);
|
int reg = parseRegister(operand1);
|
||||||
// Remove brackets from src, assuming format "[address]"
|
// Assume source is written as "[address]": remove the brackets.
|
||||||
char addrStr[32];
|
char addrStr[32];
|
||||||
strncpy(addrStr, src + 1, strlen(src) - 2);
|
strncpy(addrStr, operand2 + 1, strlen(operand2) - 2);
|
||||||
addrStr[strlen(src) - 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;
|
code[addr++] = reg;
|
||||||
code[addr++] = (memAddr >> 24) & 0xFF;
|
code[addr++] = (memAddr >> 24) & 0xFF;
|
||||||
@@ -497,12 +513,12 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
code[addr++] = (memAddr >> 8) & 0xFF;
|
code[addr++] = (memAddr >> 8) & 0xFF;
|
||||||
code[addr++] = memAddr & 0xFF;
|
code[addr++] = memAddr & 0xFF;
|
||||||
} else if (resolvedOpcode == MOV_ADDR_RN) {
|
} else if (resolvedOpcode == MOV_ADDR_RN) {
|
||||||
// dest is memory reference.
|
// Destination is memory (written as "[address]").
|
||||||
char addrStr[32];
|
char addrStr[32];
|
||||||
strncpy(addrStr, dest + 1, strlen(dest) - 2);
|
strncpy(addrStr, operand1 + 1, strlen(operand1) - 2);
|
||||||
addrStr[strlen(dest) - 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(src);
|
int reg = parseRegister(operand2);
|
||||||
code[addr++] = (memAddr >> 24) & 0xFF;
|
code[addr++] = (memAddr >> 24) & 0xFF;
|
||||||
code[addr++] = (memAddr >> 16) & 0xFF;
|
code[addr++] = (memAddr >> 16) & 0xFF;
|
||||||
code[addr++] = (memAddr >> 8) & 0xFF;
|
code[addr++] = (memAddr >> 8) & 0xFF;
|
||||||
@@ -510,136 +526,145 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
code[addr++] = reg;
|
code[addr++] = reg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// --- ALU Instructions (Arithmetic, INC/DEC, etc.) ---
|
// --- INC and DEC (baseOpcode == -12 or -13) ---
|
||||||
else if (baseOpcode < 0 && baseOpcode != -2 && baseOpcode != -11 && baseOpcode != -14 && baseOpcode != -15) {
|
// These instructions require only a single operand.
|
||||||
// For arithmetic and INC/DEC instructions, use operand2.
|
else if (baseOpcode == -12 || baseOpcode == -13) {
|
||||||
char *dest = strtok(NULL, " ,");
|
if (strlen(operand1) == 0) {
|
||||||
char *src = strtok(NULL, " ,");
|
fprintf(stderr, "Error: %s requires one operand.\n", mnemonic);
|
||||||
if (!dest || !src) {
|
return 1;
|
||||||
fprintf(stderr, "Error: %s requires two operands.\n", mnemonic);
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
int resolvedOpcode = resolveALU(baseOpcode, src);
|
int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
||||||
code[addr++] = resolvedOpcode;
|
code[addr++] = resolvedOpcode;
|
||||||
int regDest = parseRegister(dest);
|
if (operand1[0] == 'R' || operand1[0] == 'r') {
|
||||||
|
int reg = parseRegister(operand1);
|
||||||
|
code[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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// --- Other Ambiguous ALU Instructions (ADD, SUB, MUL, etc.) ---
|
||||||
|
// These require two operands (destination and source).
|
||||||
|
else if (baseOpcode < 0 && baseOpcode != -2 && baseOpcode != -11 &&
|
||||||
|
baseOpcode != -14 && baseOpcode != -15 && baseOpcode != -12 && baseOpcode != -13) {
|
||||||
|
if (strlen(operand1) == 0 || strlen(operand2) == 0) {
|
||||||
|
fprintf(stderr, "Error: %s requires two operands.\n", mnemonic);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int resolvedOpcode = resolveALU(baseOpcode, operand2);
|
||||||
|
code[addr++] = resolvedOpcode;
|
||||||
|
int regDest = parseRegister(operand1);
|
||||||
code[addr++] = regDest;
|
code[addr++] = regDest;
|
||||||
if (src[0] == 'R' || src[0] == 'r') {
|
if (operand2[0] == 'R' || operand2[0] == 'r') {
|
||||||
int regSrc = parseRegister(src);
|
int regSrc = parseRegister(operand2);
|
||||||
code[addr++] = regSrc;
|
code[addr++] = regSrc;
|
||||||
} else {
|
} else {
|
||||||
uint8_t imm = parseImmediate(src);
|
uint8_t imm = parseImmediate(operand2);
|
||||||
code[addr++] = imm;
|
code[addr++] = imm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// --- Jump Instructions ---
|
// --- JMP Instruction (baseOpcode == -11) ---
|
||||||
else if (baseOpcode == -11) { // JMP (ambiguous)
|
else if (baseOpcode == -11) {
|
||||||
// For JMP, the operand is the jump target.
|
if (strlen(operand1) == 0) {
|
||||||
char *operand = strtok(NULL, " ,");
|
fprintf(stderr, "Error: JMP requires one operand.\n");
|
||||||
if (!operand) {
|
return 1;
|
||||||
fprintf(stderr, "Error: JMP requires an operand.\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
int resolvedOpcode = resolveALU(baseOpcode, operand);
|
int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
||||||
code[addr++] = resolvedOpcode;
|
code[addr++] = resolvedOpcode;
|
||||||
if (operand[0] == '+' || operand[0] == '-') {
|
if (operand1[0] == '+' || operand1[0] == '-') {
|
||||||
// Relative jump: 1-byte offset.
|
// Relative jump: one-byte offset.
|
||||||
uint8_t offset = parseImmediate(operand);
|
uint8_t offset = parseImmediate(operand1);
|
||||||
code[addr++] = offset;
|
code[addr++] = offset;
|
||||||
} else {
|
} else {
|
||||||
// Absolute jump: 32-bit address.
|
// Absolute jump: use label lookup for 32-bit address.
|
||||||
uint32_t jumpAddr = (uint32_t) lookupLabel(operand);
|
uint32_t jumpAddr = (uint32_t) lookupLabel(operand1);
|
||||||
code[addr++] = (jumpAddr >> 24) & 0xFF;
|
code[addr++] = (jumpAddr >> 24) & 0xFF;
|
||||||
code[addr++] = (jumpAddr >> 16) & 0xFF;
|
code[addr++] = (jumpAddr >> 16) & 0xFF;
|
||||||
code[addr++] = (jumpAddr >> 8) & 0xFF;
|
code[addr++] = (jumpAddr >> 8) & 0xFF;
|
||||||
code[addr++] = jumpAddr & 0xFF;
|
code[addr++] = jumpAddr & 0xFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// --- Jump Bit Set/Clear Instructions ---
|
// --- Jump Bit Set/Clear Instructions (JMPBS, JMPBC) ---
|
||||||
else if (baseOpcode == -14 || baseOpcode == -15) {
|
else if (baseOpcode == -14 || baseOpcode == -15) {
|
||||||
// For JMPBS (jump if bit set) or JMPBC (jump if bit clear), the operand specifies the register/memory
|
if (strlen(operand1) == 0 || strlen(operand2) == 0 || strlen(operand3) == 0) {
|
||||||
// from which to test the bit, followed by the bit value and the jump target.
|
|
||||||
char *srcOperand = strtok(NULL, " ,"); // register or memory reference
|
|
||||||
char *bitToken = strtok(NULL, " ,");
|
|
||||||
char *target = strtok(NULL, " ,");
|
|
||||||
if (!srcOperand || !bitToken || !target) {
|
|
||||||
fprintf(stderr, "Error: %s requires three operands.\n", mnemonic);
|
fprintf(stderr, "Error: %s requires three operands.\n", mnemonic);
|
||||||
exit(1);
|
return 1;
|
||||||
}
|
}
|
||||||
int resolvedOpcode = resolveALU(baseOpcode, srcOperand);
|
int resolvedOpcode = resolveALU(baseOpcode, operand1);
|
||||||
code[addr++] = resolvedOpcode;
|
code[addr++] = resolvedOpcode;
|
||||||
// Encode the source operand.
|
// Encode the source operand (register or memory).
|
||||||
if (srcOperand[0] == 'R' || srcOperand[0] == 'r') {
|
if (operand1[0] == 'R' || operand1[0] == 'r') {
|
||||||
int reg = parseRegister(srcOperand);
|
int reg = parseRegister(operand1);
|
||||||
code[addr++] = reg;
|
code[addr++] = reg;
|
||||||
} else {
|
} else {
|
||||||
// Memory reference: encode 32-bit address.
|
|
||||||
char addrStr[32];
|
char addrStr[32];
|
||||||
strncpy(addrStr, srcOperand + 1, strlen(srcOperand) - 2);
|
strncpy(addrStr, operand1 + 1, strlen(operand1) - 2);
|
||||||
addrStr[strlen(srcOperand) - 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;
|
code[addr++] = (memAddr >> 24) & 0xFF;
|
||||||
code[addr++] = (memAddr >> 16) & 0xFF;
|
code[addr++] = (memAddr >> 16) & 0xFF;
|
||||||
code[addr++] = (memAddr >> 8) & 0xFF;
|
code[addr++] = (memAddr >> 8) & 0xFF;
|
||||||
code[addr++] = memAddr & 0xFF;
|
code[addr++] = memAddr & 0xFF;
|
||||||
}
|
}
|
||||||
// Encode the bit number (assumed to be a one-byte immediate).
|
// Encode the bit number (a one-byte immediate).
|
||||||
uint8_t bitVal = parseImmediate(bitToken);
|
uint8_t bitVal = parseImmediate(operand2);
|
||||||
code[addr++] = bitVal;
|
code[addr++] = bitVal;
|
||||||
// Encode the jump target as a 32-bit address.
|
// Encode the jump target (label -> 32-bit address).
|
||||||
uint32_t jumpAddr = (uint32_t) lookupLabel(target);
|
uint32_t jumpAddr = (uint32_t) lookupLabel(operand3);
|
||||||
code[addr++] = (jumpAddr >> 24) & 0xFF;
|
code[addr++] = (jumpAddr >> 24) & 0xFF;
|
||||||
code[addr++] = (jumpAddr >> 16) & 0xFF;
|
code[addr++] = (jumpAddr >> 16) & 0xFF;
|
||||||
code[addr++] = (jumpAddr >> 8) & 0xFF;
|
code[addr++] = (jumpAddr >> 8) & 0xFF;
|
||||||
code[addr++] = jumpAddr & 0xFF;
|
code[addr++] = jumpAddr & 0xFF;
|
||||||
}
|
}
|
||||||
// --- Other Instructions (CMP, SWAP, NEG, NOT, SHL, SHR, SAR, JE, JNE, JG, JL, JGE, JLE, CALL, RET) ---
|
// --- Non-ambiguous Instructions ---
|
||||||
else if (baseOpcode > 0) {
|
else if (baseOpcode > 0) {
|
||||||
// For instructions that are not ambiguous, simply encode the opcode and its operands.
|
|
||||||
switch (baseOpcode) {
|
switch (baseOpcode) {
|
||||||
case CMP:
|
case CMP:
|
||||||
case SWAP: { // Two register operands.
|
case SWAP: {
|
||||||
char *op1 = strtok(NULL, " ,");
|
if (strlen(operand1) == 0 || strlen(operand2) == 0) {
|
||||||
char *op2 = strtok(NULL, " ,");
|
|
||||||
if (!op1 || !op2) {
|
|
||||||
fprintf(stderr, "Error: %s requires two operands.\n", mnemonic);
|
fprintf(stderr, "Error: %s requires two operands.\n", mnemonic);
|
||||||
exit(1);
|
return 1;
|
||||||
}
|
}
|
||||||
code[addr++] = baseOpcode;
|
code[addr++] = baseOpcode;
|
||||||
int r1 = parseRegister(op1);
|
int r1 = parseRegister(operand1);
|
||||||
int r2 = parseRegister(op2);
|
int r2 = parseRegister(operand2);
|
||||||
code[addr++] = r1;
|
code[addr++] = r1;
|
||||||
code[addr++] = r2;
|
code[addr++] = r2;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case SWAPN:
|
case SWAPN:
|
||||||
case NEG_RN:
|
case NEG_RN:
|
||||||
case NOT_RN: { // Single register operand.
|
case NOT_RN: {
|
||||||
char *op = strtok(NULL, " ,");
|
if (strlen(operand1) == 0) {
|
||||||
if (!op) {
|
|
||||||
fprintf(stderr, "Error: %s requires one operand.\n", mnemonic);
|
fprintf(stderr, "Error: %s requires one operand.\n", mnemonic);
|
||||||
exit(1);
|
return 1;
|
||||||
}
|
}
|
||||||
code[addr++] = baseOpcode;
|
code[addr++] = baseOpcode;
|
||||||
int reg = parseRegister(op);
|
int reg = parseRegister(operand1);
|
||||||
code[addr++] = reg;
|
code[addr++] = reg;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case SHL_RN_IMM:
|
case SHL_RN_IMM:
|
||||||
case SHR_RN_IMM:
|
case SHR_RN_IMM:
|
||||||
case SAR_RN_IMM: { // Shift: register and immediate operand.
|
case SAR_RN_IMM: {
|
||||||
char *regToken = strtok(NULL, " ,");
|
if (strlen(operand1) == 0 || strlen(operand2) == 0) {
|
||||||
char *immToken = strtok(NULL, " ,");
|
|
||||||
if (!regToken || !immToken) {
|
|
||||||
fprintf(stderr, "Error: %s requires two operands.\n", mnemonic);
|
fprintf(stderr, "Error: %s requires two operands.\n", mnemonic);
|
||||||
exit(1);
|
return 1;
|
||||||
}
|
}
|
||||||
code[addr++] = baseOpcode;
|
code[addr++] = baseOpcode;
|
||||||
int reg = parseRegister(regToken);
|
int reg = parseRegister(operand1);
|
||||||
code[addr++] = reg;
|
code[addr++] = reg;
|
||||||
uint8_t imm = parseImmediate(immToken);
|
uint8_t imm = parseImmediate(operand2);
|
||||||
code[addr++] = imm;
|
code[addr++] = imm;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case JE:
|
case JE:
|
||||||
case JNE:
|
case JNE:
|
||||||
case JG:
|
case JG:
|
||||||
@@ -647,54 +672,58 @@ int secondPass(const char *source, uint8_t *code) {
|
|||||||
case JGE:
|
case JGE:
|
||||||
case JLE:
|
case JLE:
|
||||||
case CALL: {
|
case CALL: {
|
||||||
// One operand: jump target (label or immediate 32-bit address).
|
if (strlen(operand1) == 0) {
|
||||||
char *operand = strtok(NULL, " ,");
|
fprintf(stderr, "Error: %s requires one operand.\n", mnemonic);
|
||||||
if (!operand) {
|
return 1;
|
||||||
fprintf(stderr, "Error: %s requires an operand.\n", mnemonic);
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
code[addr++] = baseOpcode;
|
code[addr++] = baseOpcode;
|
||||||
if (!isdigit(operand[0])) {
|
// If the operand isn’t purely numeric, treat it as a label.
|
||||||
int labelAddr = lookupLabel(operand);
|
if (!isdigit(operand1[0])) {
|
||||||
|
int labelAddr = lookupLabel(operand1);
|
||||||
if (labelAddr < 0) {
|
if (labelAddr < 0) {
|
||||||
fprintf(stderr, "Error: undefined label '%s'\n", operand);
|
fprintf(stderr, "Error: undefined label '%s'\n", operand1);
|
||||||
exit(1);
|
return 1;
|
||||||
}
|
}
|
||||||
code[addr++] = (labelAddr >> 24) & 0xFF;
|
code[addr++] = (labelAddr >> 24) & 0xFF;
|
||||||
code[addr++] = (labelAddr >> 16) & 0xFF;
|
code[addr++] = (labelAddr >> 16) & 0xFF;
|
||||||
code[addr++] = (labelAddr >> 8) & 0xFF;
|
code[addr++] = (labelAddr >> 8) & 0xFF;
|
||||||
code[addr++] = labelAddr & 0xFF;
|
code[addr++] = labelAddr & 0xFF;
|
||||||
} else {
|
} else {
|
||||||
uint32_t immAddr = (uint32_t) strtoul(operand, NULL, 0);
|
uint32_t immAddr = (uint32_t) strtoul(operand1, NULL, 0);
|
||||||
code[addr++] = (immAddr >> 24) & 0xFF;
|
code[addr++] = (immAddr >> 24) & 0xFF;
|
||||||
code[addr++] = (immAddr >> 16) & 0xFF;
|
code[addr++] = (immAddr >> 16) & 0xFF;
|
||||||
code[addr++] = (immAddr >> 8) & 0xFF;
|
code[addr++] = (immAddr >> 8) & 0xFF;
|
||||||
code[addr++] = immAddr & 0xFF;
|
code[addr++] = immAddr & 0xFF;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case RET:
|
case RET:
|
||||||
case BRK:
|
case BRK:
|
||||||
case NOP:
|
case HLT:
|
||||||
|
case NOP: {
|
||||||
code[addr++] = baseOpcode;
|
code[addr++] = baseOpcode;
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
fprintf(stderr, "Error: Unhandled opcode %d\n", baseOpcode);
|
fprintf(stderr, "Error: Unhandled opcode %d\n", baseOpcode);
|
||||||
exit(1);
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Error: Unknown instruction '%s'\n", mnemonic);
|
fprintf(stderr, "Error: Unknown instruction '%s'\n", mnemonic);
|
||||||
exit(1);
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void completePass(const char *input, CPU *cpu, bool erase) {
|
void completePass(const char *input, CPU *cpu, bool erase) {
|
||||||
// First pass: determine label addresses.
|
// First pass: determine label addresses.
|
||||||
firstPass(input);
|
|
||||||
if (erase) {
|
if (erase) {
|
||||||
memset(cpu->memory, 0, MEM_SIZE);
|
init_cpu(cpu);
|
||||||
}
|
}
|
||||||
|
firstPass(input);
|
||||||
secondPass(input, cpu->memory);
|
secondPass(input, cpu->memory);
|
||||||
}
|
}
|
@@ -35,11 +35,15 @@ extern int labelCount;
|
|||||||
//
|
//
|
||||||
void trim(char *s);
|
void trim(char *s);
|
||||||
|
|
||||||
|
void toUpperCase(char *string);
|
||||||
|
|
||||||
|
void toLowerCase(char *string);
|
||||||
|
|
||||||
// Look up a label by name; returns -1 if not found.
|
// Look up a label by name; returns -1 if not found.
|
||||||
int lookupLabel(const char *name);
|
int lookupLabel(const char *name);
|
||||||
|
|
||||||
// Add a label to the table
|
// Add a label to the table
|
||||||
void addLabel(const char *name, int address);
|
int addLabel(const char *name, int address);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Parse a register string (e.g., "R0", "R1", etc.) and return it's number.
|
// Parse a register string (e.g., "R0", "R1", etc.) and return it's number.
|
||||||
|
16
cpu/core.c
16
cpu/core.c
@@ -9,6 +9,7 @@
|
|||||||
// Initialize CPU
|
// Initialize CPU
|
||||||
void init_cpu(CPU *cpu) {
|
void init_cpu(CPU *cpu) {
|
||||||
memset(cpu, 0, sizeof(CPU));
|
memset(cpu, 0, sizeof(CPU));
|
||||||
|
cpu->mode = CPU_MODE_HALTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function for setting flags in the CPU (here we assume bit0 is the Zero flag,
|
// Helper function for setting flags in the CPU (here we assume bit0 is the Zero flag,
|
||||||
@@ -23,7 +24,7 @@ static inline void set_flags(CPU *cpu, int32_t result) {
|
|||||||
|
|
||||||
// Execute one cycle
|
// Execute one cycle
|
||||||
void step(CPU *cpu) {
|
void step(CPU *cpu) {
|
||||||
if (!(cpu->mode & (CPU_MODE_HALTED | CPU_MODE_PAUSED | CPU_MODE_ERROR))) {
|
if (cpu->mode & (CPU_MODE_HALTED | CPU_MODE_PAUSED | CPU_MODE_ERROR)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (cpu->pc >= MEM_SIZE) {
|
if (cpu->pc >= MEM_SIZE) {
|
||||||
@@ -48,29 +49,38 @@ void step(CPU *cpu) {
|
|||||||
cpu->mode |= CPU_MODE_PAUSED;
|
cpu->mode |= CPU_MODE_PAUSED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case HLT:
|
||||||
|
//Pause CPU (for breakpoints)
|
||||||
|
cpu->mode |= CPU_MODE_HALTED;
|
||||||
|
break;
|
||||||
|
|
||||||
case INC_RN:
|
case INC_RN:
|
||||||
//Increment register
|
//Increment register
|
||||||
reg1 = read_reg_number(cpu);
|
reg1 = read_reg_number(cpu);
|
||||||
temp = read_reg(cpu, reg1);
|
temp = read_reg(cpu, reg1);
|
||||||
write_reg(cpu, reg1, temp + 1);
|
write_reg(cpu, reg1, temp + 1);
|
||||||
|
break;
|
||||||
|
|
||||||
case INC_ADDR:
|
case INC_ADDR:
|
||||||
//Increment address
|
//Increment address
|
||||||
addrTemp = read_address_argument(cpu);
|
addrTemp = read_address_argument(cpu);
|
||||||
temp = read_mem(cpu, addrTemp);
|
temp = read_mem(cpu, addrTemp);
|
||||||
write_mem(cpu, addrTemp, temp + 1);
|
write_mem(cpu, addrTemp, temp + 1);
|
||||||
|
break;
|
||||||
|
|
||||||
case DEC_RN:
|
case DEC_RN:
|
||||||
//Decrement register
|
//Decrement register
|
||||||
reg1 = read_reg_number(cpu);
|
reg1 = read_reg_number(cpu);
|
||||||
temp = read_reg(cpu, reg1);
|
temp = read_reg(cpu, reg1);
|
||||||
write_reg(cpu, reg1, temp - 1);
|
write_reg(cpu, reg1, temp - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
case DEC_ADDR:
|
case DEC_ADDR:
|
||||||
//Decrement address
|
//Decrement address
|
||||||
addrTemp = read_address_argument(cpu);
|
addrTemp = read_address_argument(cpu);
|
||||||
temp = read_mem(cpu, addrTemp);
|
temp = read_mem(cpu, addrTemp);
|
||||||
write_mem(cpu, addrTemp, temp - 1);
|
write_mem(cpu, addrTemp, temp - 1);
|
||||||
|
break;
|
||||||
|
|
||||||
case MOV_RN_IMM:
|
case MOV_RN_IMM:
|
||||||
//Load from immediate to register
|
//Load from immediate to register
|
||||||
@@ -351,7 +361,7 @@ void step(CPU *cpu) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case JMP_BIT_SET_RN: {
|
case JMP_BIT_SET_RN:
|
||||||
// Jump if bit in register set
|
// Jump if bit in register set
|
||||||
reg1 = read_reg_number(cpu);
|
reg1 = read_reg_number(cpu);
|
||||||
uint8_t bit = read_mem(cpu, cpu->pc++);
|
uint8_t bit = read_mem(cpu, cpu->pc++);
|
||||||
@@ -367,7 +377,6 @@ void step(CPU *cpu) {
|
|||||||
if (temp & (1 << bit))
|
if (temp & (1 << bit))
|
||||||
cpu->pc = newPC;
|
cpu->pc = newPC;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case JMP_BIT_SET_ADDR: {
|
case JMP_BIT_SET_ADDR: {
|
||||||
// Jump if bit in register set
|
// Jump if bit in register set
|
||||||
@@ -482,4 +491,5 @@ 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;
|
||||||
}
|
}
|
||||||
|
cpu->cycle++;
|
||||||
}
|
}
|
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#define MEM_SIZE 65535
|
#define MEM_SIZE 65535
|
||||||
// Register count (register names R0 to R7)
|
// Register count (register names R0 to R7)
|
||||||
#define REG_COUNT 32
|
#define REG_COUNT 64
|
||||||
#define STACK_SIZE 255
|
#define STACK_SIZE 255
|
||||||
|
|
||||||
#define CPU_FLAG_ZERO (1 << 0)
|
#define CPU_FLAG_ZERO (1 << 0)
|
||||||
@@ -33,6 +33,7 @@ typedef struct {
|
|||||||
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;
|
||||||
|
uint32_t cycle;
|
||||||
} CPU;
|
} CPU;
|
||||||
|
|
||||||
void step(CPU *cpu);
|
void step(CPU *cpu);
|
||||||
@@ -49,6 +50,8 @@ typedef enum {
|
|||||||
|
|
||||||
BRK, // BRK - Pause CPU (halts execution until resumed)
|
BRK, // BRK - Pause CPU (halts execution until resumed)
|
||||||
|
|
||||||
|
HLT,
|
||||||
|
|
||||||
MOV_RN_IMM, // MOV Rn, Imm - Move immediate to register (Rn = Imm)
|
MOV_RN_IMM, // MOV Rn, Imm - Move immediate to register (Rn = Imm)
|
||||||
MOV_RN_RM, // MOV Rn, Rm - Move value from one register to another (Rn = Rm)
|
MOV_RN_RM, // MOV Rn, Rm - Move value from one register to another (Rn = Rm)
|
||||||
MOV_RN_ADDR, // MOV Rn, [Addr] - Load value from memory address into register (Rn = [Addr])
|
MOV_RN_ADDR, // MOV Rn, [Addr] - Load value from memory address into register (Rn = [Addr])
|
||||||
|
20
cpu/memory.h
20
cpu/memory.h
@@ -8,29 +8,29 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "../cpu/core.h"
|
#include "../cpu/core.h"
|
||||||
|
|
||||||
inline uint8_t write_mem32(CPU *cpu, uint32_t addr, uint32_t value);
|
uint8_t write_mem32(CPU *cpu, uint32_t addr, uint32_t value);
|
||||||
|
|
||||||
inline uint8_t write_mem16(CPU *cpu, uint32_t addr, uint16_t value);
|
uint8_t write_mem16(CPU *cpu, uint32_t addr, uint16_t value);
|
||||||
|
|
||||||
inline uint32_t read_mem32(CPU *cpu, uint32_t addr);
|
uint32_t read_mem32(CPU *cpu, uint32_t addr);
|
||||||
|
|
||||||
inline uint32_t read_address_argument(CPU *cpu);
|
uint32_t read_address_argument(CPU *cpu);
|
||||||
|
|
||||||
void read_stack(CPU *cpu);
|
void read_stack(CPU *cpu);
|
||||||
|
|
||||||
void write_stack(CPU *cpu);
|
void write_stack(CPU *cpu);
|
||||||
|
|
||||||
inline uint8_t read_reg_number(CPU *cpu);
|
uint8_t read_reg_number(CPU *cpu);
|
||||||
|
|
||||||
inline uint8_t read_reg(CPU *cpu, uint8_t number);
|
uint8_t read_reg(CPU *cpu, uint8_t number);
|
||||||
|
|
||||||
inline uint8_t write_reg(CPU *cpu, uint8_t number, uint8_t value);
|
uint8_t write_reg(CPU *cpu, uint8_t number, uint8_t value);
|
||||||
|
|
||||||
inline uint16_t read_mem16(CPU *cpu, uint32_t addr);
|
uint16_t read_mem16(CPU *cpu, uint32_t addr);
|
||||||
|
|
||||||
inline uint8_t read_mem(CPU *cpu, uint32_t addr);
|
uint8_t read_mem(CPU *cpu, uint32_t addr);
|
||||||
|
|
||||||
inline uint8_t write_mem(CPU *cpu, uint32_t addr, uint8_t value);
|
uint8_t write_mem(CPU *cpu, uint32_t addr, uint8_t value);
|
||||||
|
|
||||||
|
|
||||||
#endif //RISCB_MEMORY_H
|
#endif //RISCB_MEMORY_H
|
||||||
|
305
main.c
305
main.c
@@ -4,6 +4,8 @@
|
|||||||
#include "util/font.h"
|
#include "util/font.h"
|
||||||
#include "assembler/assembler.h"
|
#include "assembler/assembler.h"
|
||||||
#include "util/texteditor.h"
|
#include "util/texteditor.h"
|
||||||
|
#include "util/hexdump.h"
|
||||||
|
#include "util/cpustatusui.h"
|
||||||
|
|
||||||
//Screen dimension constants
|
//Screen dimension constants
|
||||||
const int SCREEN_WIDTH = 1280;
|
const int SCREEN_WIDTH = 1280;
|
||||||
@@ -17,19 +19,75 @@ SDL_Window *window = NULL;
|
|||||||
//The surface contained by the window
|
//The surface contained by the window
|
||||||
SDL_Renderer *renderer = NULL;
|
SDL_Renderer *renderer = NULL;
|
||||||
|
|
||||||
BitmapFont smallFont;
|
#define biggerFont fonts[0]
|
||||||
|
#define smallFont fonts[1]
|
||||||
|
#define smallerFont fonts[2]
|
||||||
|
|
||||||
|
#define fontCount 3
|
||||||
|
|
||||||
|
BitmapFont fonts[fontCount];
|
||||||
|
|
||||||
CPU cpu;
|
CPU cpu;
|
||||||
|
|
||||||
TextEditor codeEditor;
|
SDL_Texture *cpuStatsTexture;
|
||||||
|
|
||||||
TextEditor *activeEditor;
|
SDL_Texture *cpuStateTexture;
|
||||||
|
|
||||||
|
#define codeEditor editors[0]
|
||||||
|
#define memoryViewer editors[1]
|
||||||
|
#define editorCount 2
|
||||||
|
#define activeEditor editors[activeEditorIndex]
|
||||||
|
|
||||||
|
int activeEditorIndex = 0;
|
||||||
|
TextEditor editors[editorCount];
|
||||||
|
|
||||||
|
unsigned long frames = 0;
|
||||||
|
bool cursor = true;
|
||||||
|
|
||||||
|
char *read_file_as_string(const char *filename) {
|
||||||
|
FILE *file = fopen(filename, "rb"); // Open file in binary mode
|
||||||
|
if (file == NULL) {
|
||||||
|
perror("Error opening file");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek to the end of the file to determine size
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
long filesize = ftell(file);
|
||||||
|
rewind(file); // Go back to the beginning
|
||||||
|
|
||||||
|
// Allocate memory for file content (+1 for null terminator)
|
||||||
|
char *buffer = malloc(filesize + 1);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
perror("Memory allocation failed");
|
||||||
|
fclose(file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read entire file into buffer
|
||||||
|
fread(buffer, 1, filesize, file);
|
||||||
|
buffer[filesize] = '\0'; // Null-terminate the string
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
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);
|
||||||
|
free(dump);
|
||||||
|
}
|
||||||
|
|
||||||
|
void compile(bool erase) {
|
||||||
|
generate_string(&codeEditor);
|
||||||
|
completePass(codeEditor.outputString, &cpu, erase);
|
||||||
|
updateState();
|
||||||
|
}
|
||||||
|
|
||||||
char programString[65535];
|
|
||||||
|
|
||||||
int init() {
|
int init() {
|
||||||
|
|
||||||
|
|
||||||
//Initialize SDL
|
//Initialize SDL
|
||||||
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
|
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
|
||||||
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
|
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
|
||||||
@@ -42,7 +100,6 @@ int init() {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//Create window
|
//Create window
|
||||||
window = SDL_CreateWindow("SDLko", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
|
window = SDL_CreateWindow("SDLko", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH,
|
||||||
SCREEN_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
|
SCREEN_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
|
||||||
@@ -51,39 +108,62 @@ int init() {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
//Get window surface
|
//Get window surface
|
||||||
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
init_editor(&codeEditor, &smallFont, 50, 50, renderer);
|
smallerFont = prepText(renderer, 8, "../PublicPixel.ttf", 255, 255, 255, 255);
|
||||||
activeEditor = &codeEditor;
|
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);
|
||||||
SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT);
|
SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, 0);
|
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, NULL);
|
||||||
|
for (int i = 0; i < editorCount; i++) {
|
||||||
generate_string_display(&codeEditor, renderer);
|
generate_string_display(&codeEditor, renderer);
|
||||||
|
}
|
||||||
init_cpu(&cpu);
|
init_cpu(&cpu);
|
||||||
|
compile(true);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Rect rect1;
|
|
||||||
SDL_Rect rect2;
|
|
||||||
|
|
||||||
int render() {
|
int render() {
|
||||||
SDL_SetRenderDrawColor(renderer, 128, 0, 0, 255);
|
SDL_SetRenderDrawColor(renderer, 32, 32, 32, 255);
|
||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 128, 0, 255);
|
for (int i = 0; i < editorCount; i++) {
|
||||||
rect1.x = (rect1.x + 1) % 400;
|
editor_render(&editors[i], renderer, activeEditorIndex == i, cursor);
|
||||||
rect1.y = 10;
|
}
|
||||||
rect1.w = 50;
|
|
||||||
rect1.h = 10;
|
|
||||||
SDL_RenderFillRect(renderer, &rect1);
|
|
||||||
|
|
||||||
editor_render(&codeEditor, renderer);
|
SDL_Rect rect2;
|
||||||
|
rect2.x = 9;
|
||||||
|
rect2.y = 0;
|
||||||
|
rect2.w = 0;
|
||||||
|
rect2.h = 0;
|
||||||
|
|
||||||
|
SDL_QueryTexture(cpuStatsTexture, NULL, NULL, &rect2.w, &rect2.h);
|
||||||
|
|
||||||
|
|
||||||
|
SDL_RenderCopy(renderer, cpuStatsTexture, NULL, &rect2);
|
||||||
|
|
||||||
|
rect2.x = 100;
|
||||||
|
rect2.y = 46;
|
||||||
|
rect2.w = 0;
|
||||||
|
rect2.h = 0;
|
||||||
|
|
||||||
|
SDL_QueryTexture(cpuStateTexture, NULL, NULL, &rect2.w, &rect2.h);
|
||||||
|
|
||||||
|
|
||||||
|
SDL_RenderCopy(renderer, cpuStateTexture, NULL, &rect2);
|
||||||
|
|
||||||
SDL_RenderPresent(renderer);
|
SDL_RenderPresent(renderer);
|
||||||
|
frames++;
|
||||||
|
if (!(frames % 60)) {
|
||||||
|
cursor = !cursor;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,11 +238,9 @@ SDL_Keycode ConvertKPToNonKP(SDL_Keycode keycode) {
|
|||||||
case SDLK_KP_GREATER:
|
case SDLK_KP_GREATER:
|
||||||
return SDLK_GREATER;
|
return SDLK_GREATER;
|
||||||
case SDLK_KP_AMPERSAND:
|
case SDLK_KP_AMPERSAND:
|
||||||
return SDLK_AMPERSAND;
|
|
||||||
case SDLK_KP_DBLAMPERSAND:
|
case SDLK_KP_DBLAMPERSAND:
|
||||||
return SDLK_AMPERSAND; // No direct match, best alternative
|
return SDLK_AMPERSAND; // No direct match, best alternative
|
||||||
case SDLK_KP_VERTICALBAR:
|
case SDLK_KP_VERTICALBAR:
|
||||||
return SDLK_BACKSLASH; // Vertical bar alternative
|
|
||||||
case SDLK_KP_DBLVERTICALBAR:
|
case SDLK_KP_DBLVERTICALBAR:
|
||||||
return SDLK_BACKSLASH; // No direct match
|
return SDLK_BACKSLASH; // No direct match
|
||||||
case SDLK_KP_COLON:
|
case SDLK_KP_COLON:
|
||||||
@@ -175,12 +253,6 @@ SDL_Keycode ConvertKPToNonKP(SDL_Keycode keycode) {
|
|||||||
return SDLK_AT;
|
return SDLK_AT;
|
||||||
case SDLK_KP_EXCLAM:
|
case SDLK_KP_EXCLAM:
|
||||||
return SDLK_EXCLAIM;
|
return SDLK_EXCLAIM;
|
||||||
case SDLK_KP_MEMSTORE:
|
|
||||||
return SDLK_UNKNOWN; // No direct match
|
|
||||||
case SDLK_KP_MEMRECALL:
|
|
||||||
return SDLK_UNKNOWN;
|
|
||||||
case SDLK_KP_MEMCLEAR:
|
|
||||||
return SDLK_UNKNOWN;
|
|
||||||
case SDLK_KP_MEMADD:
|
case SDLK_KP_MEMADD:
|
||||||
return SDLK_PLUS;
|
return SDLK_PLUS;
|
||||||
case SDLK_KP_MEMSUBTRACT:
|
case SDLK_KP_MEMSUBTRACT:
|
||||||
@@ -189,18 +261,15 @@ SDL_Keycode ConvertKPToNonKP(SDL_Keycode keycode) {
|
|||||||
return SDLK_ASTERISK;
|
return SDLK_ASTERISK;
|
||||||
case SDLK_KP_MEMDIVIDE:
|
case SDLK_KP_MEMDIVIDE:
|
||||||
return SDLK_SLASH;
|
return SDLK_SLASH;
|
||||||
|
case SDLK_KP_MEMSTORE:
|
||||||
|
case SDLK_KP_MEMRECALL:
|
||||||
|
case SDLK_KP_MEMCLEAR:
|
||||||
case SDLK_KP_PLUSMINUS:
|
case SDLK_KP_PLUSMINUS:
|
||||||
return SDLK_UNKNOWN;
|
|
||||||
case SDLK_KP_CLEAR:
|
case SDLK_KP_CLEAR:
|
||||||
return SDLK_UNKNOWN;
|
|
||||||
case SDLK_KP_CLEARENTRY:
|
case SDLK_KP_CLEARENTRY:
|
||||||
return SDLK_UNKNOWN;
|
|
||||||
case SDLK_KP_BINARY:
|
case SDLK_KP_BINARY:
|
||||||
return SDLK_UNKNOWN;
|
|
||||||
case SDLK_KP_OCTAL:
|
case SDLK_KP_OCTAL:
|
||||||
return SDLK_UNKNOWN;
|
|
||||||
case SDLK_KP_DECIMAL:
|
case SDLK_KP_DECIMAL:
|
||||||
return SDLK_UNKNOWN;
|
|
||||||
case SDLK_KP_HEXADECIMAL:
|
case SDLK_KP_HEXADECIMAL:
|
||||||
return SDLK_UNKNOWN;
|
return SDLK_UNKNOWN;
|
||||||
default:
|
default:
|
||||||
@@ -208,6 +277,7 @@ SDL_Keycode ConvertKPToNonKP(SDL_Keycode keycode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t cpuSpeedTemp = 0;
|
||||||
|
|
||||||
int processEvent(SDL_Event e) {
|
int processEvent(SDL_Event e) {
|
||||||
if (e.type == SDL_QUIT) { return 0; }
|
if (e.type == SDL_QUIT) { return 0; }
|
||||||
@@ -220,44 +290,144 @@ int processEvent(SDL_Event e) {
|
|||||||
SDL_RenderSetViewport(renderer, &viewport);
|
SDL_RenderSetViewport(renderer, &viewport);
|
||||||
} else if (e.type == SDL_KEYDOWN) {
|
} else if (e.type == SDL_KEYDOWN) {
|
||||||
int keySym = ConvertKPToNonKP(e.key.keysym.sym);
|
int keySym = ConvertKPToNonKP(e.key.keysym.sym);
|
||||||
|
int keyMod = e.key.keysym.mod;
|
||||||
|
cursor = true;
|
||||||
switch (keySym) {
|
switch (keySym) {
|
||||||
case SDLK_UP:
|
case SDLK_UP:
|
||||||
if (activeEditor) {
|
move_cursor_relative(&activeEditor, -1, 0, false, renderer);
|
||||||
move_cursor_relative(activeEditor, -1, 0);
|
break;
|
||||||
}
|
case SDLK_PAGEUP:
|
||||||
|
move_cursor_relative(&activeEditor, -activeEditor.max_lines_display, -1, true, renderer);
|
||||||
break;
|
break;
|
||||||
case SDLK_DOWN:
|
case SDLK_DOWN:
|
||||||
if (activeEditor) {
|
move_cursor_relative(&activeEditor, 1, 0, false, renderer);
|
||||||
move_cursor_relative(activeEditor, 1, 0);
|
break;
|
||||||
}
|
case SDLK_PAGEDOWN:
|
||||||
|
move_cursor_relative(&activeEditor, activeEditor.max_lines_display, 0, true, renderer);
|
||||||
break;
|
break;
|
||||||
case SDLK_LEFT:
|
case SDLK_LEFT:
|
||||||
if (activeEditor) {
|
move_cursor_relative(&activeEditor, 0, -1, false, renderer);
|
||||||
move_cursor_relative(activeEditor, 0, -1);
|
break;
|
||||||
|
case SDLK_HOME:
|
||||||
|
if (keyMod & KMOD_CTRL) {
|
||||||
|
move_cursor(&activeEditor, 0, 0, false, renderer);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
move_cursor(&activeEditor, activeEditor.cursor_line, 0, false, renderer);
|
||||||
break;
|
break;
|
||||||
case SDLK_RIGHT:
|
case SDLK_RIGHT:
|
||||||
if (activeEditor) {
|
move_cursor_relative(&activeEditor, 0, 1, false, renderer);
|
||||||
move_cursor_relative(activeEditor, 0, 1);
|
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);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
move_cursor(&activeEditor, activeEditor.cursor_line, lineLen, false, renderer);
|
||||||
|
break;
|
||||||
|
case SDLK_F9:
|
||||||
|
cpu.mode ^= CPU_MODE_LOOP;
|
||||||
|
updateState();
|
||||||
|
return 1;
|
||||||
|
case SDLK_F8:
|
||||||
|
if (++cpuSpeedTemp == 3) {
|
||||||
|
cpuSpeedTemp = 0;
|
||||||
|
}
|
||||||
|
cpu.mode &= ~(CPU_MODE_SECOND | CPU_MODE_STEP);
|
||||||
|
cpu.mode |= cpuSpeedTemp << 4;
|
||||||
|
updateState();
|
||||||
|
return 1;
|
||||||
|
case SDLK_F5:
|
||||||
|
compile(!(keyMod & KMOD_CTRL));
|
||||||
|
case SDLK_F7:
|
||||||
|
if (cpu.mode & (CPU_MODE_HALTED | CPU_MODE_ERROR) || (keyMod & KMOD_SHIFT)) {
|
||||||
|
cpu.pc = 0;
|
||||||
|
}
|
||||||
|
cpu.mode &= ~(CPU_MODE_HALTED | CPU_MODE_PAUSED | CPU_MODE_ERROR);
|
||||||
|
updateState();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_ESCAPE:
|
||||||
|
cpu.mode |= CPU_MODE_PAUSED;
|
||||||
|
if (keyMod & (KMOD_CTRL | KMOD_SHIFT)) {
|
||||||
|
cpu.mode |= CPU_MODE_HALTED;
|
||||||
|
}
|
||||||
|
updateState();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_s:
|
||||||
|
if (keyMod & KMOD_CTRL) {
|
||||||
|
FILE *fptr;
|
||||||
|
char fname[20];
|
||||||
|
snprintf(fname, sizeof(fname), "riscb%lu.bsm", time(NULL));
|
||||||
|
fptr = fopen(fname, "w");
|
||||||
|
generate_string(&editors[0]);
|
||||||
|
fputs(editors[0].outputString, fptr);
|
||||||
|
fclose(fptr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_l:
|
||||||
|
if (keyMod & KMOD_CTRL) {
|
||||||
|
FILE *fptr;
|
||||||
|
char fname[20];
|
||||||
|
sscanf(editors[0].lines[0].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);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDLK_BACKSPACE:
|
||||||
|
if (!activeEditor.readOnly) {
|
||||||
|
remove_character(&activeEditor, false, renderer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDLK_DELETE:
|
||||||
|
if (!activeEditor.readOnly) {
|
||||||
|
remove_character(&activeEditor, true, renderer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDLK_RETURN:
|
case SDLK_RETURN:
|
||||||
case SDLK_RETURN2:
|
case SDLK_RETURN2:
|
||||||
if (activeEditor && !activeEditor->readOnly) {
|
if (keyMod & KMOD_CTRL && activeEditorIndex == 0) {
|
||||||
insert_line_rel(activeEditor, renderer);
|
compile(!(keyMod & KMOD_SHIFT));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if (!activeEditor.readOnly) {
|
||||||
|
insert_line_rel(&activeEditor, renderer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDLK_TAB:
|
||||||
|
activeEditorIndex++;
|
||||||
|
if (activeEditorIndex >= editorCount) {
|
||||||
|
activeEditorIndex = 0;
|
||||||
|
}
|
||||||
|
activeEditor = editors[activeEditorIndex];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (activeEditor && !activeEditor->readOnly && activeEditor->cursor_pos < MAX_LINE_WIDTH) {
|
} else if (e.type == SDL_TEXTINPUT) {
|
||||||
if (keySym >= 32 && keySym <= 126) {
|
for (int i = 0; e.text.text[i] != '\0'; i++) { // Iterate over the input string
|
||||||
if (keySym > 0x60 && keySym < 0x7b) {
|
char keySym = e.text.text[i];
|
||||||
|
|
||||||
|
if (!activeEditor.readOnly && activeEditor.cursor_pos <= activeEditor.max_line_width) {
|
||||||
|
if (keySym >= 32 && keySym <= 126) { // Printable ASCII range
|
||||||
|
if (keySym > 0x60 && keySym < 0x7b) { // Convert lowercase to uppercase
|
||||||
keySym -= 0x20;
|
keySym -= 0x20;
|
||||||
}
|
}
|
||||||
insert_character(activeEditor, (keySym & 0xff), renderer);
|
if (activeEditor.cursor_pos < activeEditor.max_line_width) {
|
||||||
} else if (keySym == SDLK_BACKSPACE || keySym == SDLK_DELETE) {
|
insert_character(&activeEditor, keySym, renderer);
|
||||||
remove_character(activeEditor, renderer);
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,6 +456,22 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(cpu.mode & (CPU_MODE_HALTED | CPU_MODE_PAUSED | CPU_MODE_ERROR))) {
|
||||||
|
if (cpu.mode & CPU_MODE_SECOND) {
|
||||||
|
if (frames % 60) {
|
||||||
|
step(&cpu);
|
||||||
|
updateState();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
step(&cpu);
|
||||||
|
updateState();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu.mode & CPU_MODE_STEP) {
|
||||||
|
cpu.mode |= CPU_MODE_PAUSED;
|
||||||
|
updateState();
|
||||||
|
}
|
||||||
|
}
|
||||||
end = SDL_GetTicks64();
|
end = SDL_GetTicks64();
|
||||||
const unsigned long timeNeeded = end - start;
|
const unsigned long timeNeeded = end - start;
|
||||||
if (timeNeeded < delayNeeded) {
|
if (timeNeeded < delayNeeded) {
|
||||||
@@ -295,12 +481,13 @@ int main(__attribute__((unused)) int argc, __attribute__((unused)) char *args[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *program;
|
for (uint8_t i = 0; i < editorCount; i++) {
|
||||||
int program_size;
|
destroy_editor(&editors[i]);
|
||||||
|
}
|
||||||
|
|
||||||
completePass(programString, &cpu, true);
|
for (uint8_t i = 0; i < fontCount; i++) {
|
||||||
|
destroyFont(&fonts[i]);
|
||||||
step(&cpu);
|
}
|
||||||
|
|
||||||
//Destroy window
|
//Destroy window
|
||||||
SDL_DestroyWindow(window);
|
SDL_DestroyWindow(window);
|
||||||
|
168
util/cpustatusui.c
Normal file
168
util/cpustatusui.c
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
//
|
||||||
|
// Created by bruno on 8.2.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <SDL2/SDL_render.h>
|
||||||
|
#include "cpustatusui.h"
|
||||||
|
#include "font.h"
|
||||||
|
|
||||||
|
SDL_Texture *renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont,
|
||||||
|
SDL_Renderer *renderer) {
|
||||||
|
|
||||||
|
CPUStatusPart *stats = NULL;
|
||||||
|
int statsCount = 0;
|
||||||
|
|
||||||
|
|
||||||
|
getStats(cpu, &stats, &statsCount);
|
||||||
|
|
||||||
|
const int padding = 4;
|
||||||
|
const int oneFieldW = (titleFont->size + 1) * (sizeof(stats[0].value) - 1) + 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);
|
||||||
|
|
||||||
|
SDL_SetRenderTarget(renderer, out);
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
|
for (int i = 0; i < statsCount; i++) {
|
||||||
|
int x = i * oneFieldW;
|
||||||
|
SDL_Rect rect = {x, 0, oneFieldW, oneFieldH};
|
||||||
|
SDL_SetRenderDrawColor(renderer, 50, 50, 50, 255);
|
||||||
|
SDL_RenderFillRect(renderer, &rect);
|
||||||
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
||||||
|
SDL_RenderDrawRect(renderer, &rect);
|
||||||
|
|
||||||
|
// Render the title
|
||||||
|
int textX = x + padding;
|
||||||
|
int textY = padding;
|
||||||
|
for (int j = 0; j < 6 && stats[i].name[j] != '\0'; j++) {
|
||||||
|
SDL_Texture *charTex = titleFont->texture[(uint8_t) stats[i].name[j]];
|
||||||
|
if (charTex) {
|
||||||
|
SDL_Rect dstRect = {textX, textY, titleFont->size, titleFont->size};
|
||||||
|
SDL_RenderCopy(renderer, charTex, NULL, &dstRect);
|
||||||
|
textX += titleFont->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the value
|
||||||
|
char valueStr[12];
|
||||||
|
snprintf(valueStr, sizeof(valueStr), "%u", stats[i].value);
|
||||||
|
textX = x + padding;
|
||||||
|
textY += titleFont->size + padding;
|
||||||
|
for (int j = 0; valueStr[j] != '\0'; j++) {
|
||||||
|
SDL_Texture *charTex = valueFont->texture[(uint8_t) valueStr[j]];
|
||||||
|
if (charTex) {
|
||||||
|
SDL_Rect dstRect = {textX, textY, valueFont->size, valueFont->size};
|
||||||
|
SDL_RenderCopy(renderer, charTex, NULL, &dstRect);
|
||||||
|
textX += valueFont->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_SetRenderTarget(renderer, NULL);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void getStats(CPU *cpu, CPUStatusPart **cpuStatus, int *cpuStatusCount) {
|
||||||
|
if (!cpu || !cpuStatus || !cpuStatusCount) return;
|
||||||
|
|
||||||
|
int count = 5 + REG_COUNT; // PC, SP, FLAGS, MODE, CYCLE + registers
|
||||||
|
|
||||||
|
// Free existing memory if allocated
|
||||||
|
if (*cpuStatus) {
|
||||||
|
free(*cpuStatus);
|
||||||
|
*cpuStatus = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the required memory
|
||||||
|
*cpuStatus = (CPUStatusPart *) malloc(count * sizeof(CPUStatusPart));
|
||||||
|
if (!*cpuStatus) return; // Memory allocation failed
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
strncpy((*cpuStatus)[index].name, "PC", sizeof((*cpuStatus)[index].name));
|
||||||
|
(*cpuStatus)[index].value = cpu->pc;
|
||||||
|
index++;
|
||||||
|
|
||||||
|
strncpy((*cpuStatus)[index].name, "SP", sizeof((*cpuStatus)[index].name));
|
||||||
|
(*cpuStatus)[index].value = cpu->stack_ptr;
|
||||||
|
index++;
|
||||||
|
|
||||||
|
strncpy((*cpuStatus)[index].name, "FLG", sizeof((*cpuStatus)[index].name));
|
||||||
|
(*cpuStatus)[index].value = cpu->flags;
|
||||||
|
index++;
|
||||||
|
|
||||||
|
strncpy((*cpuStatus)[index].name, "MOD", sizeof((*cpuStatus)[index].name));
|
||||||
|
(*cpuStatus)[index].value = cpu->mode;
|
||||||
|
index++;
|
||||||
|
|
||||||
|
strncpy((*cpuStatus)[index].name, "CYC", sizeof((*cpuStatus)[index].name));
|
||||||
|
(*cpuStatus)[index].value = cpu->cycle;
|
||||||
|
index++;
|
||||||
|
|
||||||
|
for (int i = 0; i < 25; i++) {
|
||||||
|
snprintf((*cpuStatus)[index].name, sizeof((*cpuStatus)[index].name), "R%d", i);
|
||||||
|
(*cpuStatus)[index].value = cpu->regs[i];
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*cpuStatusCount = index; // Store the actual number of status parts
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Texture *renderState(CPU *cpu, BitmapFont *titleFont, SDL_Renderer *renderer) {
|
||||||
|
|
||||||
|
// Render the value
|
||||||
|
char valueStr[20] = "";
|
||||||
|
if (cpu->mode & CPU_MODE_ERROR) {
|
||||||
|
strcat(valueStr, "ERR ");
|
||||||
|
} else if (cpu->mode & CPU_MODE_HALTED) {
|
||||||
|
strcat(valueStr, "HLT ");
|
||||||
|
} else if (cpu->mode & CPU_MODE_PAUSED) {
|
||||||
|
strcat(valueStr, "PAUS ");
|
||||||
|
} else {
|
||||||
|
strcat(valueStr, "RUN ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu->mode & CPU_MODE_LOOP) {
|
||||||
|
strcat(valueStr, "LOOP ");
|
||||||
|
} else {
|
||||||
|
strcat(valueStr, "ONCE ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cpu->mode & CPU_MODE_STEP) {
|
||||||
|
strcat(valueStr, "STP");
|
||||||
|
} else if (cpu->mode & CPU_MODE_SECOND) {
|
||||||
|
strcat(valueStr, "SEC");
|
||||||
|
} else {
|
||||||
|
strcat(valueStr, "BRR");
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
SDL_SetRenderTarget(renderer, out);
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
|
SDL_Rect rect = {0, 0, allFieldW, oneFieldH};
|
||||||
|
SDL_SetRenderDrawColor(renderer, 50, 50, 50, 255);
|
||||||
|
SDL_RenderFillRect(renderer, &rect);
|
||||||
|
|
||||||
|
|
||||||
|
int x = 0;
|
||||||
|
for (int j = 0; valueStr[j] != '\0'; j++) {
|
||||||
|
SDL_Texture *charTex = titleFont->texture[(uint8_t) valueStr[j]];
|
||||||
|
if (charTex) {
|
||||||
|
SDL_Rect dstRect = {x, 0, titleFont->size, titleFont->size};
|
||||||
|
x += titleFont->size + 1;
|
||||||
|
SDL_RenderCopy(renderer, charTex, NULL, &dstRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_SetRenderTarget(renderer, NULL);
|
||||||
|
return out;
|
||||||
|
}
|
23
util/cpustatusui.h
Normal file
23
util/cpustatusui.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// Created by bruno on 8.2.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef RISCB_CPUSTATUSUI_H
|
||||||
|
#define RISCB_CPUSTATUSUI_H
|
||||||
|
|
||||||
|
#include "font.h"
|
||||||
|
#include "../cpu/core.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char name[4];
|
||||||
|
uint32_t value;
|
||||||
|
} CPUStatusPart;
|
||||||
|
|
||||||
|
SDL_Texture *renderVals(CPU *cpu, BitmapFont *titleFont, BitmapFont *valueFont,
|
||||||
|
SDL_Renderer *renderer);
|
||||||
|
|
||||||
|
SDL_Texture *renderState(CPU *cpu, BitmapFont *titleFont, SDL_Renderer *renderer);
|
||||||
|
|
||||||
|
void getStats(CPU *cpu, CPUStatusPart **cpuStatus, int *cpuStatusCount);
|
||||||
|
|
||||||
|
#endif //RISCB_CPUSTATUSUI_H
|
11
util/font.c
11
util/font.c
@@ -10,13 +10,13 @@ prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file, uint8_t
|
|||||||
BitmapFont out;
|
BitmapFont out;
|
||||||
out.size = pxSize;
|
out.size = pxSize;
|
||||||
out.color = (SDL_Color) {r, g, b, a};
|
out.color = (SDL_Color) {r, g, b, a};
|
||||||
unsigned char i = 0;
|
unsigned int i = 1;
|
||||||
do {
|
do {
|
||||||
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 < 255);
|
} while (i < 256);
|
||||||
|
|
||||||
TTF_CloseFont(gFont);
|
TTF_CloseFont(gFont);
|
||||||
return out;
|
return out;
|
||||||
@@ -44,3 +44,10 @@ void renderText(SDL_Renderer *renderer, BitmapFont font, char *string, uint16_t
|
|||||||
string++;
|
string++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void destroyFont(BitmapFont *font) {
|
||||||
|
for (uint16_t i = 1; i < 256; i++) {
|
||||||
|
SDL_DestroyTexture(font->texture[i]);
|
||||||
|
SDL_FreeSurface(font->surface[i]);
|
||||||
|
}
|
||||||
|
}
|
@@ -19,6 +19,8 @@ typedef struct {
|
|||||||
BitmapFont
|
BitmapFont
|
||||||
prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
prepText(SDL_Renderer *renderer, unsigned char pxSize, const char *file, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
||||||
|
|
||||||
|
void destroyFont(BitmapFont *font);
|
||||||
|
|
||||||
void renderText(SDL_Renderer *renderer, BitmapFont font, char *string, uint16_t x, uint16_t y);
|
void renderText(SDL_Renderer *renderer, BitmapFont font, char *string, uint16_t x, uint16_t y);
|
||||||
|
|
||||||
#endif //RISCB_FONT_H
|
#endif //RISCB_FONT_H
|
||||||
|
50
util/hexdump.c
Normal file
50
util/hexdump.c
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// Created by bruno on 6.2.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "hexdump.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#define BYTES_PER_LINE 16 // Adjust for different widths
|
||||||
|
|
||||||
|
|
||||||
|
char *hexdump_to_string(const unsigned char *data, size_t size) {
|
||||||
|
// Estimate max output size: each line is approx. 80 chars
|
||||||
|
size_t estimated_size = (size / BYTES_PER_LINE + 1) * 80;
|
||||||
|
|
||||||
|
// Allocate memory for output string
|
||||||
|
char *output = malloc(estimated_size);
|
||||||
|
if (!output) return NULL;
|
||||||
|
|
||||||
|
size_t offset = 0; // Track the write position
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size; i += BYTES_PER_LINE) {
|
||||||
|
offset += snprintf(output + offset, estimated_size - offset, "%08zx ", 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]);
|
||||||
|
else
|
||||||
|
offset += snprintf(output + offset, estimated_size - offset, " "); // Padding
|
||||||
|
if (j == 7) offset += snprintf(output + offset, estimated_size - 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
12
util/hexdump.h
Normal file
12
util/hexdump.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// Created by bruno on 6.2.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef RISCB_HEXDUMP_H
|
||||||
|
#define RISCB_HEXDUMP_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
char *hexdump_to_string(const unsigned char *data, size_t size);
|
||||||
|
|
||||||
|
#endif //RISCB_HEXDUMP_H
|
@@ -1,62 +1,120 @@
|
|||||||
///
|
//
|
||||||
// Created by bruno on 5.2.2025.
|
// Created by bruno on 5.2.2025.
|
||||||
///
|
// Modified to use dynamic limits.
|
||||||
|
//
|
||||||
|
|
||||||
#include "texteditor.h"
|
#include "texteditor.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
|
||||||
// Initialize the text editor
|
// 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,
|
||||||
for (int i = 0; i < MAX_LINES_ASM; i++) {
|
int max_line_width, int max_lines_asm, int max_lines_display, bool readOnly) {
|
||||||
editor->lines[i].text[0] = '\0'; // Empty string
|
editor->max_line_width = max_line_width;
|
||||||
editor->lines[i].active = 0;
|
editor->max_lines_asm = max_lines_asm;
|
||||||
}
|
editor->max_lines_display = max_lines_display;
|
||||||
editor->lines[0].active = 1;
|
editor->line_count = 0;
|
||||||
editor->line_count = 1;
|
|
||||||
editor->cursor_line = 0;
|
editor->cursor_line = 0;
|
||||||
editor->cursor_line_offset = 0;
|
editor->cursor_line_offset = 0;
|
||||||
editor->cursor_pos = 0;
|
editor->cursor_pos = 0;
|
||||||
editor->readOnly = 0;
|
editor->readOnly = readOnly;
|
||||||
editor->rect.x = 2;
|
|
||||||
editor->rect.y = 2;
|
|
||||||
editor->rect.w = MAX_LINE_WIDTH * (font->size + 1);
|
|
||||||
editor->rect.h = MAX_LINES_DISPLAY * (font->size + 4);
|
|
||||||
editor->outRect = editor->rect;
|
|
||||||
editor->outRect.x = x;
|
|
||||||
editor->outRect.y = y;
|
|
||||||
editor->font = font;
|
editor->font = font;
|
||||||
editor->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, editor->rect.w,
|
|
||||||
editor->rect.h);
|
editor->outRect = malloc(sizeof(SDL_Rect));
|
||||||
|
editor->cursorRect = malloc(sizeof(SDL_Rect));
|
||||||
|
editor->rect = 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));
|
||||||
|
|
||||||
|
|
||||||
|
// Allocate dynamic array for lines.
|
||||||
|
editor->lines = (Line *) malloc(sizeof(Line) * editor->max_lines_asm);
|
||||||
|
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++) {
|
||||||
|
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);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
editor->lines[i].text[0] = '\0';
|
||||||
|
editor->lines[i].active = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
if (!editor->outputString || !editor->displayString) {
|
||||||
|
fprintf(stderr, "Failed to allocate memory for output/display strings.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
editor->outputString[0] = '\0';
|
||||||
|
editor->displayString[0] = '\0';
|
||||||
|
|
||||||
|
// Initialize with two active lines (like the original code).
|
||||||
|
editor->lines[0].active = 1;
|
||||||
|
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.
|
||||||
|
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->outRect->w = editor->rect->w;
|
||||||
|
editor->outRect->h = editor->rect->h;
|
||||||
|
editor->outRect->x = x;
|
||||||
|
editor->outRect->y = y;
|
||||||
|
|
||||||
|
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->h = editor->font->size;
|
||||||
|
|
||||||
|
// Create texture for rendering.
|
||||||
|
editor->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888,
|
||||||
|
SDL_TEXTUREACCESS_TARGET,
|
||||||
|
editor->rect->w, editor->rect->h);
|
||||||
|
if (!editor->texture) {
|
||||||
|
fprintf(stderr, "Failed to create texture: %s\n", SDL_GetError());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert a new line at a specific position
|
// 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 >= MAX_LINES_ASM || position < 0 || position > editor->line_count) {
|
if (editor->line_count >= editor->max_lines_asm || position < 0 || position > editor->line_count) {
|
||||||
printf("Invalid position or max lines reached!\n");
|
printf("Invalid position or max lines reached!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shift lines down if necessary
|
// Shift lines down.
|
||||||
for (int i = editor->line_count; i > position; i--) {
|
for (int i = editor->line_count; i > position; 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(editor->lines[position].text, text, MAX_LINE_WIDTH);
|
// Copy the text into the new line, ensuring it does not exceed max_line_width.
|
||||||
editor->lines[position].text[MAX_LINE_WIDTH] = '\0'; // Ensure null termination
|
strncpy(editor->lines[position].text, text, editor->max_line_width);
|
||||||
|
editor->lines[position].text[editor->max_line_width] = '\0';
|
||||||
editor->lines[position].active = 1;
|
editor->lines[position].active = 1;
|
||||||
|
|
||||||
editor->line_count++;
|
editor->line_count++;
|
||||||
|
move_cursor(editor, editor->cursor_line + 1, 0, false, renderer);
|
||||||
generate_string_display(editor, renderer);
|
generate_string_display(editor, renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
editor->cursor_pos = 0;
|
editor->cursor_pos = 0;
|
||||||
insert_line(editor, editor->cursor_line + 1, "", renderer);
|
|
||||||
editor->cursor_line++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert a character at the current cursor position
|
|
||||||
void insert_character(TextEditor *editor, char ch, SDL_Renderer *renderer) {
|
void insert_character(TextEditor *editor, char ch, SDL_Renderer *renderer) {
|
||||||
if (editor->cursor_line < 0 || editor->cursor_line >= editor->line_count) {
|
if (editor->cursor_line < 0 || editor->cursor_line >= editor->line_count) {
|
||||||
printf("Invalid cursor position!\n");
|
printf("Invalid cursor position!\n");
|
||||||
@@ -66,12 +124,12 @@ void insert_character(TextEditor *editor, char ch, SDL_Renderer *renderer) {
|
|||||||
Line *line = &editor->lines[editor->cursor_line];
|
Line *line = &editor->lines[editor->cursor_line];
|
||||||
int len = strlen(line->text);
|
int len = strlen(line->text);
|
||||||
|
|
||||||
if (len >= MAX_LINE_WIDTH || editor->cursor_pos > len) {
|
if (len >= editor->max_line_width || editor->cursor_pos > len) {
|
||||||
printf("Position out of bounds or line is full!\n");
|
printf("Position out of bounds or line is full!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shift characters to the right
|
// Shift characters to the right.
|
||||||
for (int i = len; i >= editor->cursor_pos; i--) {
|
for (int i = len; i >= editor->cursor_pos; i--) {
|
||||||
line->text[i + 1] = line->text[i];
|
line->text[i + 1] = line->text[i];
|
||||||
}
|
}
|
||||||
@@ -81,14 +139,26 @@ void insert_character(TextEditor *editor, char ch, SDL_Renderer *renderer) {
|
|||||||
generate_string_display(editor, renderer);
|
generate_string_display(editor, renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_character(TextEditor *editor, SDL_Renderer *renderer) {
|
void remove_character(TextEditor *editor, bool isDelete, SDL_Renderer *renderer) {
|
||||||
if (editor->cursor_line < 0 || editor->cursor_line >= editor->line_count) {
|
if (editor->cursor_line < 0 || editor->cursor_line >= editor->line_count) {
|
||||||
printf("Invalid cursor position!\n");
|
printf("Invalid cursor position!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Line *line = &editor->lines[editor->cursor_line];
|
||||||
|
int len = strlen(line->text);
|
||||||
|
|
||||||
|
if (isDelete) {
|
||||||
|
// Delete character after cursor
|
||||||
|
if (editor->cursor_pos < len) {
|
||||||
|
for (int i = editor->cursor_pos; i < len; i++) {
|
||||||
|
line->text[i] = line->text[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Backspace behavior (delete character before cursor)
|
||||||
if (editor->cursor_pos == 0 && editor->line_count > 1) {
|
if (editor->cursor_pos == 0 && editor->line_count > 1) {
|
||||||
// Remove the current line and shift lines up
|
// Merge with the previous line
|
||||||
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;
|
||||||
@@ -100,120 +170,189 @@ void remove_character(TextEditor *editor, SDL_Renderer *renderer) {
|
|||||||
editor->cursor_line = editor->line_count - 1;
|
editor->cursor_line = editor->line_count - 1;
|
||||||
}
|
}
|
||||||
editor->cursor_pos = strlen(editor->lines[editor->cursor_line].text);
|
editor->cursor_pos = strlen(editor->lines[editor->cursor_line].text);
|
||||||
} else {
|
} else if (editor->cursor_pos > 0) {
|
||||||
Line *line = &editor->lines[editor->cursor_line];
|
|
||||||
int len = strlen(line->text);
|
|
||||||
|
|
||||||
if (editor->cursor_pos <= 0 || editor->cursor_pos > len) {
|
|
||||||
printf("Position out of bounds!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shift characters to the left to remove the character
|
|
||||||
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];
|
||||||
}
|
}
|
||||||
|
|
||||||
editor->cursor_pos--;
|
editor->cursor_pos--;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
generate_string_display(editor, renderer);
|
generate_string_display(editor, renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Move cursor
|
void move_cursor_relative(TextEditor *editor, int line_offset, int pos_offset, bool keepPos, SDL_Renderer *renderer) {
|
||||||
void move_cursor_relative(TextEditor *editor, int line_offset, int pos_offset) {
|
|
||||||
int new_line = editor->cursor_line + line_offset;
|
int new_line = editor->cursor_line + line_offset;
|
||||||
int new_pos = editor->cursor_pos + pos_offset;
|
int new_pos = editor->cursor_pos + pos_offset;
|
||||||
|
|
||||||
if (new_line < 0) new_line = 0;
|
move_cursor(editor, new_line, new_pos, keepPos, renderer);
|
||||||
if (new_line >= editor->line_count) new_line = editor->line_count - 1;
|
|
||||||
|
|
||||||
move_cursor(editor, new_line, new_pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move cursor
|
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) {
|
|
||||||
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;
|
if (new_line >= editor->line_count) new_line = editor->line_count - 1;
|
||||||
|
|
||||||
|
if (keepPos) {
|
||||||
|
editor->cursor_line_offset = new_line;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
int line_length = strlen(editor->lines[new_line].text);
|
int line_length = strlen(editor->lines[new_line].text);
|
||||||
if (new_pos < 0) new_pos = 0;
|
if (new_pos < 0) new_pos = 0;
|
||||||
if (new_pos > line_length) new_pos = line_length;
|
if (new_pos > line_length) new_pos = line_length;
|
||||||
|
|
||||||
editor->cursor_line = new_line;
|
editor->cursor_line = new_line;
|
||||||
editor->cursor_pos = new_pos;
|
editor->cursor_pos = new_pos;
|
||||||
|
generate_string_display(editor, renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a string from a given offset with a max line count
|
|
||||||
void generate_string_display(TextEditor *editor, SDL_Renderer *renderer) {
|
void generate_string_display(TextEditor *editor, SDL_Renderer *renderer) {
|
||||||
if (editor->cursor_line_offset < 0 || editor->cursor_line_offset >= editor->line_count) {
|
if (editor->cursor_line_offset < 0 || editor->cursor_line_offset >= editor->line_count) {
|
||||||
printf("Invalid start line!\n");
|
printf("Invalid start line!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int end_line = editor->cursor_line_offset + MAX_LINES_DISPLAY;
|
int end_line = editor->cursor_line_offset + editor->max_lines_display;
|
||||||
if (end_line > editor->line_count) end_line = editor->line_count;
|
if (end_line > editor->line_count)
|
||||||
|
end_line = editor->line_count;
|
||||||
|
|
||||||
|
// Clear the display string.
|
||||||
memset(editor->displayString, 0, sizeof(editor->displayString));
|
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, 255);
|
||||||
SDL_RenderClear(renderer);
|
SDL_RenderClear(renderer);
|
||||||
|
|
||||||
|
SDL_Rect charDstRect;
|
||||||
|
charDstRect.x = 4;
|
||||||
|
charDstRect.y = 3;
|
||||||
|
charDstRect.w = editor->font->size;
|
||||||
|
charDstRect.h = editor->font->size;
|
||||||
|
|
||||||
SDL_Rect charRect;
|
SDL_Rect charRect;
|
||||||
charRect.x = 0;
|
charRect.x = 0;
|
||||||
charRect.y = 0;
|
charRect.y = 0;
|
||||||
charRect.w = editor->font->size;
|
charRect.w = editor->font->size;
|
||||||
charRect.h = editor->font->size;
|
charRect.h = editor->font->size;
|
||||||
SDL_Rect outRect = charRect;
|
|
||||||
outRect.x = 3;
|
|
||||||
outRect.y = 2;
|
|
||||||
|
|
||||||
SDL_Rect cursorRect;
|
editor->cursorRect->x = 3 + editor->cursor_pos * (charDstRect.w + 1) + editor->outRect->x;
|
||||||
cursorRect.x = 0;
|
editor->cursorRect->y =
|
||||||
cursorRect.y = 0;
|
2 + (editor->cursor_line - editor->cursor_line_offset) * (charDstRect.h + 1) + editor->outRect->y;
|
||||||
cursorRect.w = 1;
|
|
||||||
cursorRect.h = editor->font->size;
|
|
||||||
|
|
||||||
for (int line = editor->cursor_line_offset; line < end_line; line++) {
|
for (int line = editor->cursor_line_offset; line < end_line; line++) {
|
||||||
if (editor->lines[line].active) {
|
if (editor->lines[line].active) {
|
||||||
strcat(editor->displayString, editor->lines[line].text);
|
strcat(editor->displayString, editor->lines[line].text);
|
||||||
char *linePTR = editor->lines[line].text;
|
char *linePTR = editor->lines[line].text;
|
||||||
int charIndex = 0;
|
|
||||||
while (*linePTR) {
|
while (*linePTR) {
|
||||||
SDL_RenderCopy(renderer, editor->font->texture[*linePTR], &charRect, &outRect);
|
SDL_RenderCopy(renderer, editor->font->texture[(unsigned char) *linePTR], &charRect, &charDstRect);
|
||||||
outRect.x += charRect.w + 1;
|
charDstRect.x += charDstRect.w + 1;
|
||||||
if (line == editor->cursor_line && charIndex == editor->cursor_pos - 1) {
|
|
||||||
cursorRect.x = outRect.x;
|
|
||||||
cursorRect.y = outRect.y;
|
|
||||||
}
|
|
||||||
charIndex++;
|
|
||||||
linePTR++;
|
linePTR++;
|
||||||
}
|
}
|
||||||
strcat(editor->displayString, "\n");
|
strcat(editor->displayString, "\n");
|
||||||
outRect.x = 3;
|
charDstRect.x = 4;
|
||||||
outRect.y += charRect.h + 1;
|
charDstRect.y += charDstRect.h + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
|
|
||||||
SDL_RenderFillRect(renderer, &cursorRect);
|
|
||||||
SDL_SetRenderTarget(renderer, NULL);
|
SDL_SetRenderTarget(renderer, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void editor_render(TextEditor *editor, SDL_Renderer *renderer) {
|
void editor_render(TextEditor *editor, SDL_Renderer *renderer, bool isActive, bool cursorBlink) {
|
||||||
SDL_RenderCopy(renderer, editor->texture, &editor->rect, &editor->outRect);
|
if (isActive) {
|
||||||
|
SDL_Rect bgRect;
|
||||||
|
bgRect = *editor->outRect;
|
||||||
|
bgRect.x -= 6;
|
||||||
|
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);
|
||||||
|
if (isActive && cursorBlink) {
|
||||||
|
SDL_SetRenderDrawColor(renderer, 0, 255, 255, 255);
|
||||||
|
SDL_RenderFillRect(renderer, editor->cursorRect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a string for assembling
|
|
||||||
void generate_string(TextEditor *editor) {
|
void generate_string(TextEditor *editor) {
|
||||||
memset(editor->outputString, 0, sizeof(editor->outputString));
|
editor->outputString[0] = '\0';
|
||||||
|
|
||||||
for (int i = 0; i < MAX_LINES_ASM; i++) {
|
for (int i = 0; i < editor->max_lines_asm; i++) {
|
||||||
if (editor->lines[i].active) {
|
if (editor->lines[i].active) {
|
||||||
|
if (strlen(editor->lines[i].text)) {
|
||||||
strcat(editor->outputString, editor->lines[i].text);
|
strcat(editor->outputString, editor->lines[i].text);
|
||||||
strcat(editor->outputString, "\n");
|
strcat(editor->outputString, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fill_editor_from_string(TextEditor *editor, const char *content, SDL_Renderer *renderer) {
|
||||||
|
if (!editor || !content) {
|
||||||
|
printf("Invalid editor or content pointer!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the current editor content
|
||||||
|
for (int i = 0; i < editor->max_lines_asm; i++) {
|
||||||
|
editor->lines[i].text[0] = '\0';
|
||||||
|
editor->lines[i].active = 0;
|
||||||
|
}
|
||||||
|
editor->line_count = 0;
|
||||||
|
editor->cursor_line = 0;
|
||||||
|
editor->cursor_pos = 0;
|
||||||
|
|
||||||
|
// Parse the content and fill the editor lines
|
||||||
|
const char *ptr = content;
|
||||||
|
int line_index = 0;
|
||||||
|
|
||||||
|
while (*ptr && line_index < editor->max_lines_asm) {
|
||||||
|
int char_count = 0;
|
||||||
|
|
||||||
|
// Ensure the text buffer does not overflow
|
||||||
|
while (*ptr && *ptr != '\n' && char_count < editor->max_line_width - 1) {
|
||||||
|
editor->lines[line_index].text[char_count++] = *ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
editor->lines[line_index].text[char_count] = '\0'; // Null-terminate
|
||||||
|
editor->lines[line_index].active = 1;
|
||||||
|
line_index++;
|
||||||
|
|
||||||
|
// Move past the newline character if present
|
||||||
|
if (*ptr == '\n') ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the total number of lines in use
|
||||||
|
editor->line_count = line_index;
|
||||||
|
|
||||||
|
// Generate the visual representation
|
||||||
|
generate_string_display(editor, renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Free all dynamically allocated memory.
|
||||||
|
void destroy_editor(TextEditor *editor) {
|
||||||
|
if (editor->lines) {
|
||||||
|
for (int i = 0; i < editor->max_lines_asm; i++) {
|
||||||
|
free(editor->lines[i].text);
|
||||||
|
}
|
||||||
|
free(editor->lines);
|
||||||
|
}
|
||||||
|
free(editor->outputString);
|
||||||
|
free(editor->displayString);
|
||||||
|
|
||||||
|
free(editor->outRect);
|
||||||
|
free(editor->rect);
|
||||||
|
free(editor->cursorRect);
|
||||||
|
|
||||||
|
if (editor->texture) {
|
||||||
|
SDL_DestroyTexture(editor->texture);
|
||||||
|
}
|
||||||
}
|
}
|
@@ -1,67 +1,72 @@
|
|||||||
///
|
//
|
||||||
// Created by bruno on 5.2.2025.
|
// Created by bruno on 5.2.2025.
|
||||||
///
|
// Modified to use dynamic limits.
|
||||||
|
//
|
||||||
#ifndef RISCB_TEXTEDITOR_H
|
#ifndef RISCB_TEXTEDITOR_H
|
||||||
#define RISCB_TEXTEDITOR_H
|
#define RISCB_TEXTEDITOR_H
|
||||||
|
|
||||||
#define MAX_LINE_WIDTH 34 // Max chars per line (excluding '\0')
|
|
||||||
#define MAX_LINES_ASM 100 // Max number of lines
|
|
||||||
#define MAX_LINES_DISPLAY 10 // Max number of lines
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <SDL2/SDL_rect.h>
|
#include <SDL2/SDL_rect.h>
|
||||||
#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"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char text[MAX_LINE_WIDTH + 1]; // +1 for null terminator
|
char *text; // Dynamically allocated string for this line
|
||||||
int active; // Flag to check if the line is in use
|
int active; // Flag to check if the line is in use
|
||||||
} Line;
|
} Line;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Line lines[MAX_LINES_ASM]; // 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 max_line_width; // Maximum characters per line (excluding '\0')
|
||||||
|
int max_lines_display; // Maximum number of lines for display
|
||||||
|
|
||||||
int cursor_line; // Current cursor line
|
int cursor_line; // Current cursor line
|
||||||
int cursor_line_offset; // Current cursor line
|
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[MAX_LINE_WIDTH * MAX_LINES_ASM];
|
|
||||||
char displayString[MAX_LINE_WIDTH * MAX_LINES_DISPLAY];
|
char *outputString; // Dynamically allocated output string (size: max_line_width * max_lines_asm + 1)
|
||||||
SDL_Rect rect;
|
char *displayString; // Dynamically allocated display string (size: max_line_width * max_lines_display + 1)
|
||||||
SDL_Rect outRect;
|
SDL_Rect *rect;
|
||||||
|
SDL_Rect *outRect;
|
||||||
SDL_Texture *texture;
|
SDL_Texture *texture;
|
||||||
bool readOnly;
|
bool readOnly;
|
||||||
BitmapFont *font;
|
BitmapFont *font;
|
||||||
|
SDL_Rect *cursorRect;
|
||||||
} TextEditor;
|
} TextEditor;
|
||||||
|
|
||||||
// Initialize the text editor
|
// Initialize the text editor. The parameters max_line_width, max_lines_asm, and max_lines_display
|
||||||
void init_editor(TextEditor *editor, BitmapFont *font, int x, int y, SDL_Renderer *renderer);
|
// 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);
|
||||||
|
|
||||||
// Insert a new line at a specific position
|
// Other function prototypes remain mostly unchanged but will use the dynamic limits:
|
||||||
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);
|
||||||
|
|
||||||
// Insert a new line at a specific position
|
|
||||||
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);
|
void editor_render(TextEditor *editor, SDL_Renderer *renderer, bool isActive, bool cursorBlink);
|
||||||
|
|
||||||
void remove_character(TextEditor *editor, SDL_Renderer *renderer);
|
void remove_character(TextEditor *editor, bool isDelete, SDL_Renderer *renderer);
|
||||||
|
|
||||||
// Insert a character at the current cursor position
|
|
||||||
void insert_character(TextEditor *editor, char ch, SDL_Renderer *renderer);
|
void insert_character(TextEditor *editor, char ch, SDL_Renderer *renderer);
|
||||||
|
|
||||||
// Move cursor (handled externally)
|
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);
|
|
||||||
|
|
||||||
// Move cursor (handled externally)
|
void move_cursor_relative(TextEditor *editor, int line_offset, int pos_offset, bool keepPos, SDL_Renderer *renderer);
|
||||||
void move_cursor_relative(TextEditor *editor, int line_offset, int pos_offset);
|
|
||||||
|
|
||||||
// Generate a string from a given offset with a max line count
|
|
||||||
void generate_string_display(TextEditor *editor, SDL_Renderer *renderer);
|
void generate_string_display(TextEditor *editor, SDL_Renderer *renderer);
|
||||||
|
|
||||||
void generate_string(TextEditor *editor);
|
void generate_string(TextEditor *editor);
|
||||||
|
|
||||||
#endif //RISCB_TEXTEDITOR_H
|
void fill_editor_from_string(TextEditor *editor, const char *content, SDL_Renderer *renderer);
|
||||||
|
|
||||||
|
// A cleanup function to free dynamically allocated memory.
|
||||||
|
void destroy_editor(TextEditor *editor);
|
||||||
|
|
||||||
|
#endif // RISCB_TEXTEDITOR_H
|
||||||
|
Reference in New Issue
Block a user