Added stuff. Fixed bug.

Data Pointer value now properly displayed in debug mode.
Added conditional calls to match conditional branches.
This commit is contained in:
Anachronaut
2024-10-31 13:30:15 -04:00
committed by GitHub
parent f8848adf8c
commit 228cf0593a
12 changed files with 414 additions and 44 deletions
+128
View File
@@ -0,0 +1,128 @@
; print.asm
; Some simple SplitBit subroutines for printing.
; Anachronaut
; 10/27/2024
#Program
BRI start ; Branch immediately to the start of the program.
lineFeed:
INIA 0x0A ; Load the character for linefeed into A.
OUTA 0x00 ; Output it.
RET ; Return to the caller.
; Expects A to contain the number of spaces to print.
blankSpace:
INIB 0x20 ; Set B to the ASCII value for space.
OUTB 0x00 ; Print it.
BRA printDone ; If A is zero, we're done.
DECA ; Decrement A.
BRI blankSpace ; Branch back to the loop again.
printString: ; Expects Data Pointer to be set to the beginning of the string to be printed.
LDA ; Move the first character of the string into A.
BRA printDone ; If A is NULL, the string is finished, so return.
OUTA 0x00 ; Output the character.
INCD ; Increment Data Pointer to the next character.
BRI printString ; Branch to the beginning of the loop.
printDone:
RET ; Return to the caller.
; Expects A to contain the value to be printed in decimal form.
printByteDecimal:
; Clear the buffer we're going to write into.
SETD DecimalValue ; Set the Data Pointer to the buffer.
RSTB ; Set B to 0.
STB ; Store it in the buffer.
INCD ; Increment to the tens place.
STB ; Store 0 in it.
INCD ; Increment to the hundred's place.
STB ; Store 0 in it.
INIB 0d10 ; Load 10 into B.
PSHA ; Save the value onto the stack.
printDecimalLoopStart:
POPA ; Pop the value to A from the stack.
CCF ; Clear the Carry Flag.
SUB ; Subtract 10 from the value in A.
BRC getOnes ; If 10 is bigger than A, We're done looping and A contains the ones.
BRA getOnes ; If the value 0, we're also done.
; Otherwise, increment the tens place.
SETD DecimalValue ; Set the Data Pointer to the buffer.
INCD ; Increment to the tens place.
PSHQ ; Save the new value onto the stack.
LDA ; Load the number of tens into A.
INCA ; Increment it.
; Now check to see if there are ten tens and we need to carry to the hundreds.
CCF ; Clear the Carry Flag.
SUB ; Subtract 10 from A.
BRQ incrementHundreds ; If Q is 0, set the tens to 0 and increment the hundreds place.
STA ; Otherwise, store the value back to the tens place.
BRI printDecimalLoopStart ; and loop again.
incrementHundreds:
STQ ; Store 0 in the tens place.
INCD ; Increment the Data Pointer to the hundreds place.
LDA ; Load it into A.
INCA ; Increment it.
STA ; Store it back again.
BRI printDecimalLoopStart ; and Loop again.
getOnes:
SETD DecimalValue ; Set the Data Pointer to the ones place.
STA ; Store A in it.
; At this point we're done. We just need to print the digits with the printDecimalDigit subroutine.
INCD INCD ; Increment the Data Pointer twice to the hundreds place.
decimalCheckLoop:
LDA ; Load the value into A.
BRA checkTens ; If the hundreds are 0, skip printing their digit.
CALL printDecimalDigit ; Otherwise, print it.
DECD
LDA
CALL printDecimalDigit ; And the tens place, too.
BRI printOnes ; And finally, the ones.
checkTens:
DECD ; Decrement to the tens place.
LDA ; Load it into A.
BRA printOnes ; If the tens are zero, skip printing their digit, too.
CALL printDecimalDigit ; Otherwise, print it.
printOnes:
DECD ; Decrement to the ones place.
LDA
CALL printDecimalDigit ; Print it no matter what.
RET ; We're done, return to the caller.
; Expects A to contain the byte you want to print as a hexadecimal value.
printByteHex:
INIB 0x00 ; Set B to 0.
SHR SHR SHR SHR ; Shift Right four times to move the high nybble into the lower half of A.
CALL printHexDigit ; Print the nybble.
INIA 0x00 ; Set A to 0.
SHL SHL SHL SHL ; Shift left four times to move the low nybble back into the lower half of A.
CALL printHexDigit ; Print the nybble.
RET ; Return to the caller.
; Expects A to contain the nybble you want to print.
printHexDigit:
INIB 0d10 ; Set B to 10.
SUB ; Subtract it.
BRC printDecimalDigit ; If the Carry Flag is set, the digit is less than 9. Print it.
; Since it's greater than 9, add the ASCII offset for capital letters.
INIB 0x37 ; Set B to the offset.
ADD ; Add it to A.
OUTQ 0x00 ; Print the result.
RET ; Return to the caller.
; Expects A to contain a single BCD digit to print.
printDecimalDigit:
INIB 0x30 ; Load ASCII offset for numbers into B.
CCF ; Clear the Carry Flag.
ADD ; Add it to A.
OUTQ 0x00 ; Send it to the output.
RET ; Return from subroutine.
#Data
; This is where printDecimal stores its result.
DecimalValue:
0x00 ; The ones place.
0x00 ; The tens place.
0x00 ; The hundreds place.
+3 -3
View File
@@ -5,7 +5,7 @@
; 10/27/2024 ; 10/27/2024
; Include the subroutine file. ; Include the subroutine file.
#Include print.asm #Include Libraries/print.asm
#Program #Program
@@ -14,12 +14,12 @@ start:
CALL printString ; Call the string printing subroutine. CALL printString ; Call the string printing subroutine.
CALL lineFeed ; Call the line feed subroutine to end the line. CALL lineFeed ; Call the line feed subroutine to end the line.
SETD MyDecimal ; Set the Data Pointer to the value to print as a decimal. SETD MyDecimal ; Set the Data Pointer to the value to print as a decimal.
CALL printDecimal ; Call the decimal printing subroutine. LDA ; Load it into A.
CALL printByteDecimal ; Call the decimal printing subroutine.
SETD MyMessage ; Set the Data Pointer to another string. SETD MyMessage ; Set the Data Pointer to another string.
CALL printString ; Call the string printing subroutine again. CALL printString ; Call the string printing subroutine again.
CALL lineFeed ; Call the line feed subroutine to end the line. CALL lineFeed ; Call the line feed subroutine to end the line.
HALT ; Stop the program. HALT ; Stop the program.
#Data #Data
MyString: MyString:
@@ -0,0 +1,25 @@
; Tests for the printDecimal subroutine.
#Program
printByteDecimalTest:
INIB 0xFF ; Load 255 into B.
printDecimalTestloop:
SUB
CCF ; Clear the Carry Flag.
CALL printByteDecimal ; Print the value.
INCA ; Increment it.
PSHA
INIA 0x00
CALL blankSpace
POPA
BRQ printDecimalTestend ; If Q is zero, we're done.
BRI printDecimalTestloop ; Branch back to the start of the loop.
printDecimalTestend:
CALL lineFeed
RET
#Data
Space:
" "
+17
View File
@@ -0,0 +1,17 @@
#Program
printDigitTest:
INIB 0d10
printDigitTestLoop:
CALL printDecimalDigit
INCA
SUB
CCF
BRQ printDigitTestend
CALL lineFeed
BRI printDigitTestLoop
printDigitTestend:
CALL lineFeed
RET
#Data
+22
View File
@@ -0,0 +1,22 @@
; Test for the hexadecimal printing routines.
#Program
printByteHexTest:
INIB 0xFF
CALL printByteHex
printHexTestLoop:
PSHA
INIA 0x00
CALL blankSpace
POPA
INCA
SUB
CCF
CALL printByteHex
BRQ printHexTestend
BRI printHexTestLoop
printHexTestend:
CALL lineFeed
RET
#Data
+58
View File
@@ -0,0 +1,58 @@
; Tests for the printing subroutines provided by print.asm
#Include ../Libraries/print.asm
#Include printDigitTest.asm
#Include printDecimalTest.asm
#Include printHexTest.asm
#Program
clearRegisters:
INIA 0x00;
INIB 0x00;
ADD
RET
start:
SETD String0
CALL printString
CALL lineFeed
SETD String1
CALL printString
CALL lineFeed
CALL clearRegisters
CALL printDigitTest
CALL lineFeed
SETD String2
CALL printString
CALL lineFeed
CALL clearRegisters
CALL printByteDecimalTest
CALL lineFeed
SETD String3
CALL printString
CALL lineFeed
CALL clearRegisters
CALL printByteHexTest
CALL lineFeed
SETD String4
CALL printString
CALL lineFeed
HALT
#Data
String0:
"Test suite for SplitBit's print.asm library."
String1:
"Testing printDigit..."
String2:
"Testing printByteDecimal..."
String3:
"Testing printByteHex..."
String4:
"Testing complete!"
+84
View File
@@ -0,0 +1,84 @@
; A simple test for the new SHL and SHR instructions.
#Include print.asm
#Program
start:
SETD String0
CALL printString
loop0:
SETD TestValue0
CALL printDecimal
LDA
SHL
STA
SETD Space
CALL printString
BRA doB
BRI loop0
doB:
CALL lineFeed
SETD String1
CALL printString
SETD TestValue0
STB
loop1:
SETD TestValue0
CALL printDecimal
LDB
SHL
STB
SETD Space
CALL printString
BRB doRight
BRA loop1
doRight:
CALL lineFeed
SETD String0
CALL printString
loop2:
SETD TestValue1
CALL printDecimal
LDA
SHR
STA
SETD Space
CALL printString
BRA doRightB
BRI loop2
doRightB:
CALL lineFeed
SETD String1
CALL printString
SETD TestValue1
STB
loop3:
SETD TestValue1
CALL printDecimal
LDB
SHR
STB
SETD Space
CALL printString
BRB end
BRA loop3
end:
CALL lineFeed
HALT
#Data
TestValue0:
0d01
TestValue1:
0d128
String0:
"A values: "
String1:
"B values: "
Space:
" "
+7 -3
View File
@@ -29,9 +29,13 @@ Instruction instruction_set[] = {
{0x11, "BRQ"}, {0x11, "BRQ"},
{0x12, "BRA"}, {0x12, "BRA"},
{0x13, "BRB"}, {0x13, "BRB"},
{0x14, "CALL"}, {0x14, "BRC"},
{0x15, "RET"}, {0x17, "CALL"},
{0x16, "BRC"}, {0x18, "CALLA"},
{0x19, "CALLB"},
{0x1A, "CALLQ"},
{0x1B, "CALLCF"},
{0x1F, "RET"},
// Register Operations: // Register Operations:
{0x20, "RSTA"}, {0x20, "RSTA"},
{0x21, "RSTB"}, {0x21, "RSTB"},
+1 -1
View File
@@ -112,7 +112,7 @@ void populateOutputBuffers(intermediateElement *intermediateArray, int arraySize
Program[(*programCount)++] = intermediateArray[i].byteValue; Program[(*programCount)++] = intermediateArray[i].byteValue;
// Check if it's a branch instruction. // Check if it's a branch instruction.
if (((intermediateArray[i].byteValue & 0xF0) == 0x10) && (intermediateArray[i].byteValue != 0x15)){ if (((intermediateArray[i].byteValue & 0xF0) == 0x10) && (intermediateArray[i].byteValue != 0x1F)){
if (intermediateArray[i + 1].type != LABEL) { if (intermediateArray[i + 1].type != LABEL) {
fprintf(stderr, RED "Error: Branch without label.\n" RESET); fprintf(stderr, RED "Error: Branch without label.\n" RESET);
printf("File: %s at line %d.\n", intermediateArray[i].fileName, intermediateArray[i].lineNumber); printf("File: %s at line %d.\n", intermediateArray[i].fileName, intermediateArray[i].lineNumber);
+59 -32
View File
@@ -31,6 +31,31 @@ void genericBranch(CPURegisters *cpu){
cpu->ProgramCounter = DestinationAddress-1; cpu->ProgramCounter = DestinationAddress-1;
} }
void genericCall(CPURegisters *cpu){
// Order, low byte, high byte
cpu->Data[cpu->StackPointer] = cpu->ProgramCounter & 0xFF;
cpu->StackPointer--;
cpu->Data[cpu->StackPointer] = (cpu->ProgramCounter >> 8) & 0xFF;
cpu->StackPointer--;
// Push the Data Pointer to the Stack.
// Order, low byte, high byte
cpu->Data[cpu->StackPointer] = cpu->DataPointer & 0xFF;
cpu->StackPointer--;
cpu->Data[cpu->StackPointer] = (cpu->DataPointer >> 8) & 0xFF;
cpu->StackPointer--;
// Push Q to the Stack.
cpu->Data[cpu->StackPointer] = cpu->Q;
cpu->StackPointer--;
// Push B to the Stack.
cpu->Data[cpu->StackPointer] = cpu->B;
cpu->StackPointer--;
// Push A to the Stack.
cpu->Data[cpu->StackPointer] = cpu->A;
cpu->StackPointer--;
// Perform a Generic Branch to the Address.
genericBranch(cpu);
}
uint8_t executeOperation(uint8_t Instruction, CPURegisters *cpu) { uint8_t executeOperation(uint8_t Instruction, CPURegisters *cpu) {
switch(Instruction) { switch(Instruction) {
// 0x - Arithmetic and Logic Operations. // 0x - Arithmetic and Logic Operations.
@@ -131,31 +156,41 @@ uint8_t executeOperation(uint8_t Instruction, CPURegisters *cpu) {
} }
break; break;
case 0x14: case 0x14:
// CALL - Push the Program Counter to the Stack, and perform an immediate branch. // BRC - Do an immediate branch if the Carry Flag is set.
// Order, low byte, high byte if (cpu->Status & 0x01) {
cpu->Data[cpu->StackPointer] = cpu->ProgramCounter & 0xFF; genericBranch(cpu);
cpu->StackPointer--; } else {
cpu->Data[cpu->StackPointer] = (cpu->ProgramCounter >> 8) & 0xFF; cpu->ProgramCounter+=2;
cpu->StackPointer--; }
// Push the Data Pointer to the Stack.
// Order, low byte, high byte
cpu->Data[cpu->StackPointer] = cpu->DataPointer & 0xFF;
cpu->StackPointer--;
cpu->Data[cpu->StackPointer] = (cpu->DataPointer >> 8) & 0xFF;
cpu->StackPointer--;
// Push Q to the Stack.
cpu->Data[cpu->StackPointer] = cpu->Q;
cpu->StackPointer--;
// Push B to the Stack.
cpu->Data[cpu->StackPointer] = cpu->B;
cpu->StackPointer--;
// Push A to the Stack.
cpu->Data[cpu->StackPointer] = cpu->A;
cpu->StackPointer--;
// Perform a Generic Branch to the Address.
genericBranch(cpu);
break; break;
case 0x15: case 0x17:
// CALL - Push the Program Counter to the Stack, and perform an immediate branch.
genericCall(cpu);
break;
case 0x18:
// CALLA
if (cpu->A == 0) {
genericCall(cpu);
}
break;
case 0x19:
// CALLB
if (cpu->B == 0) {
genericCall(cpu);
}
break;
case 0x1A:
// CALLQ
if (cpu->Q == 0) {
genericCall(cpu);
}
case 0x1B:
// CALLCF
if (cpu->Status & 0x01) {
genericCall(cpu);
}
break;
case 0x1F:
// RET - Return from subroutine, restore the registers and set the Program Counter to the Return Address. // RET - Return from subroutine, restore the registers and set the Program Counter to the Return Address.
// Pop A from the Stack. // Pop A from the Stack.
cpu->StackPointer++; cpu->StackPointer++;
@@ -179,14 +214,6 @@ uint8_t executeOperation(uint8_t Instruction, CPURegisters *cpu) {
// Add 2 to the Program Counter to skip over the address when it returns. // Add 2 to the Program Counter to skip over the address when it returns.
cpu->ProgramCounter += 2; cpu->ProgramCounter += 2;
break; break;
case 0x16:
// BRC - Do an immediate branch is the Carry Flag is set.
if (cpu->Status & 0x01) {
genericBranch(cpu);
} else {
cpu->ProgramCounter+=2;
}
break;
// //
// 2x - Register Operations: // 2x - Register Operations:
// //
+1 -1
View File
@@ -51,6 +51,6 @@ void printRegisters(CPURegisters *cpu, uint8_t *Program, uint8_t *Data) {
printf("A: 0x%02X\tB: 0x%02X\tQ: 0x%02X\tStatus: 0b%08b\n", cpu->A, cpu->B, cpu->Q, cpu->Status); printf("A: 0x%02X\tB: 0x%02X\tQ: 0x%02X\tStatus: 0b%08b\n", cpu->A, cpu->B, cpu->Q, cpu->Status);
printf("Program Counter: 0x%04X Current Instruction: 0x%02X (%s)\n", cpu->ProgramCounter, Program[cpu->ProgramCounter],getMnemonic(Program[cpu->ProgramCounter])); printf("Program Counter: 0x%04X Current Instruction: 0x%02X (%s)\n", cpu->ProgramCounter, Program[cpu->ProgramCounter],getMnemonic(Program[cpu->ProgramCounter]));
printf(" Data Pointer: 0x%04X Current Data Value: 0x%02X\n", cpu->DataPointer, Data[cpu->DataPointer]); printf(" Data Pointer: 0x%04X Current Data Value: 0x%02X\n", cpu->DataPointer, Data[cpu->DataPointer]);
printf(" Stack Pointer: 0x%04X Current Value: (0x%02X) (0x%02X)\n", Data[cpu->StackPointer], Data[cpu->StackPointer+1], Data[cpu->StackPointer+2]); printf(" Stack Pointer: 0x%04X Current Value: (0x%02X) (0x%02X)\n", cpu->StackPointer, Data[cpu->StackPointer+1], Data[cpu->StackPointer+2]);
} }
+8 -3
View File
@@ -38,9 +38,14 @@ Hex Code | Mnemonic | Description
11 | BRQ | Branch on Q. If Q is zero, loads the immediate next two bytes of Program Memory into the Program Counter. 11 | BRQ | Branch on Q. If Q is zero, loads the immediate next two bytes of Program Memory into the Program Counter.
12 | BRA | Branch on A. If A is zero, loads the immediate next two bytes of Program Memory into the Program Counter. 12 | BRA | Branch on A. If A is zero, loads the immediate next two bytes of Program Memory into the Program Counter.
13 | BRB | Branch on B. If B is zero, loads the immediate next two bytes of Program Memory into the Program Counter. 13 | BRB | Branch on B. If B is zero, loads the immediate next two bytes of Program Memory into the Program Counter.
14 | CALL | Stores all the registers to the Stack, A, B, Q, the Data Pointer, and the Program Counter, then performs an immediate branch. 14 | BRC | Branch if Carry is set.
15 | RET | Restores all registers from the Stack, then immediately branches to the Return Address by setting the Program Counter to the next instruction after the last CALL. 17 | CALL | Call subroutine. Stores all the registers to the Stack, A, B, Q, the Data Pointer, and the Program Counter, then performs an immediate branch.
16 | BRC | Branch if Carry is set. 18 | CALLA | Conditional Call on A. Calls subroutine if A is zero.
19 | CALLB | Conditional Call on B. Calls subroutine if B is zero.
1A | CALLQ | Conditional Call on Q. Calls subroutine if Q is zero.
1B | CALLCF | Conditional Call on Carry. Calls subroutine if the Carry Flag is set.
1F | RET | Restores all registers from the Stack, then immediately branches to the Return Address by setting the Program Counter to the next instruction after the last CALL.
### Register Operations: 11 Instructions ### Register Operations: 11 Instructions
| Hex Code | Mnemonic | Description | | Hex Code | Mnemonic | Description |