According to this made-up microprocessor architecture's instruction set: https://github.com/mertyildiran/DASM
In our toy assembler written in C, we have implemented PUSH & POP instructions as shown below:
PUSH:
Which is basically the combination of 4 DEC and 1 ST instruction.
else if (strcmp(token,"push")==0) // PUSH instruction: combination of 4 DEC and 1 ST instruction on Stack Pointer (SP)
{
op1 = strtok(NULL,"\n\t\r ");
op2[0] = sp; // Let's say address of SP is 9
printf("\n\t%s\t%s\n",strupr(token),op1);
ch = (op2[0]-48) | ((op2[0]-48)<<3); // Prepare bitwise instruction format for DEC instructions
program[counter]=0x7800+((ch)&0x00ff); // Decrease Stack Pointer 4 times
printf("> %d\t%04x\n",counter,program[counter]);
counter++;
program[counter]=0x7800+((ch)&0x00ff); // Decrease Stack Pointer 4 times
printf("> %d\t%04x\n",counter,program[counter]);
counter++;
program[counter]=0x7800+((ch)&0x00ff); // Decrease Stack Pointer 4 times
printf("> %d\t%04x\n",counter,program[counter]);
counter++;
program[counter]=0x7800+((ch)&0x00ff); // Decrease Stack Pointer 4 times
printf("> %d\t%04x\n",counter,program[counter]);
counter++;
ch = ((op1[0]-48) << 2) | ((op2[0]-48) << 6); // Prepare bitwise instruction format for ST instruction
program[counter]=0x3000+((ch)&0x00ff); // Store the value in Stack
printf("> %d\t%04x\n",counter,program[counter]);
counter++;
}
POP:
Which is basically the combination of 1 LD and 4 INC instructions.
else if (strcmp(token,"pop")==0) // POP instruction: combination of 1 LD and 4 INC instructions on Stack Pointer (SP)
{
op1 = strtok(NULL,"\n\t\r ");
op2[0] = sp; // Let's say address of SP is 9
printf("\n\t%s\t%s\n",strupr(token),op1);
ch = (op1[0]-48) | ((op2[0]-48) << 3); // Prepare bitwise instruction format for LD instruction
program[counter]=0x2000+((ch)&0x00ff); // Store the value in Stack
printf("> %d\t%04x\n",counter,program[counter]);
counter++;
ch = (op2[0]-48) | ((op2[0]-48)<<3); // Prepare bitwise instruction format for INC instructions
program[counter]=0x7700+((ch)&0x00ff); // Decrease Stack Pointer 4 times
printf("> %d\t%04x\n",counter,program[counter]);
counter++;
program[counter]=0x7700+((ch)&0x00ff); // Decrease Stack Pointer 4 times
printf("> %d\t%04x\n",counter,program[counter]);
counter++;
program[counter]=0x7700+((ch)&0x00ff); // Decrease Stack Pointer 4 times
printf("> %d\t%04x\n",counter,program[counter]);
counter++;
program[counter]=0x7700+((ch)&0x00ff); // Decrease Stack Pointer 4 times
printf("> %d\t%04x\n",counter,program[counter]);
counter++;
}
So my question is how can we implement CALL & RET instructions with using a stack?
I'm aware that CALL instruction will store current state of PC in the stack so the program will be able to return where it left with RET instruction. But it's leading me to two subquestions:
- After CALL executed, how the program get address previously stored in the stack if in the subprocedure, an instruction PUSHed something to the stack or overwrite the return address of CALL.
- How can we pass the related label's address to CALL in machine code level? In our assembler JMP & jZ instructions are also not completed, because of the same reason.
If you want to look at the whole picture: https://github.com/mertyildiran/DASM/blob/master/assembler.c
For 2. subquestion(JMP/CALL) you can explain it over this example with maybe jmp lpp
line:
.data
count: 60
array: .space 10
char: 0xfe
.code
ldi 0 count
ld 0 0
ldi 1 array
ldi 2 char
ld 2 2
lpp st 1 2
inc 1
dec 0
jz loop
jmp lpp
loop sub 1 2 3
lp1 jmp lp1