hi,
i musst write a programm in C hbut i dont understand this. i dont know how to do it. i hope someone can help e.
i wait for your answer.
Create a CPU simulator for the model CPU detailed in the lecture Digital Systems. The CPU simulator shall be able to
load an assembly file provided either at startup as a command-line argument or after invocation via a dedicated command: ld <file>,
run/execute the program either up to a set breakpoint or until to the end of the program:r,
single step through the program: s,
display the content of the CPU internal registers dr and provide a memory dump: dm,
support (set/clear) for one breakpoint: bs <line>, bc and
quit the program: q.
Output shall be written to the screen and (optional) also to a log file that is simple the given assembly-program name (e.g. sum.c), however, instead with an extension *.log (e.g. sum.log).
The instruction set that shall be supported is defined in the file Instruction Set of the Model CPU on the pages of the lecture Digital Systems on PDF-pages 5-14. This instruction set shall be enhanced by the following assembly commands (shown as examples) for the simulator:
var .dw <var_value>
... reserves space for a variable named var with a value var_value
Example:
va .dw 0x1234 ; reserve space for variable va and initialize it with the
; hex value 0x1234
const .equ <const_val>
... defines a constant named const that has the value of const_val;
constants do not reserve memory and are replaced in the code before execution
(like the #define statment in the C programming language)
Example:
ca .equ 5 ; define a constant ca with the decimal value 5
reg .dr <reg_val>
... initializes a register reg:={a, sp, ix, fp} with the value of reg_val
Example:
a .dr 0x1010 ; initialize the accu with the hex value 0x1010
sp .dr 512 ; initialize the stack pointer with the decimal
; value 512
f .df <flag_val>
... initializes a flag f:={c, s, z, o} with the value of flag_val
Example:
c .df 1 ; set the carry flag
.org <addr>
... defines the start address for the following commands starting at addr;
every further command is offset by one word (16 bits)
Example:
.org 64 ; the following statements are located from address 64 onwards
.end
... defines the end of the code
Furthermore, symbolic labels (alphanumeric strings starting with an underline character and terminated by a colon and line comments (a line comment starts with a semi-colon shall be supported. All numbers are either decimal or when prefixed by 0x hexadecimal.
Example program (see the script CPU Progarmmers Model on pages 56-68 for a detailed explanation and discussion):
; a simple program that adds two constants using a sub-routine and stores
; the result in a variable vc
;
ca .equ 5 ; define a constant ca with value 5
cb .equ 7 ; define a constant cb with value 7
.org 128
vc .dw 0 ; define a variable vc at address 128 (= 0x80) with value 0
.org 0
_main:
lda,c ca ; load constant ca to accu
push,r a ; push accu to the stack
lda,c cb ; load constant cb to accu
push,r a ; push accu to the stack
call sum ; call sub-routine sum
sta vc ; vc = accu
inc,r sp,2 ; deallocate parameter stack
jmp _end ; jmp to label end
_sum:
push,r fp ; save old framepointer
ldr fp,sp ; mark current frame
dec,r sp,1 ; space for temp below the fp
lda,c 0 ; accu = 0
sta,ri fp,-1 ; temp = accu
lda,ri fp,2 ; accu = 7 (via stack)
add,ri fp,3 ; accu = 7 + 5 (via stack)
sta,ri fp,-1 ; temp = accu
lda,ri fp,-1 ; accu = temp
ldr sp,fp ; remove locals from stack
pop,r fp ; restore fp of caller
ret ; back to caller
_end:
.end
In a first step the input file must be pre-processed in order to produce the following intermediate representation that is fed as input to the CPU simulator. In particular
remove all comments,
replace all constants with their values and remove the definition lines containing the constants,
map the commands to address locations evaluating and replacing the .org commands (the entire address range is linear covering 2^9 address locations),
replace the labels within the code with addresses and replace the variable names with their locations that were assigned in the previous step.
Finally write the initial values of the variables to the according locations.
After the above steps you will end up with something like in the following listing. 0x000:
0x002:
0x004:
0x006:
0x008:
0x010:
0x012:
0x014:
0x016:
0x018:
0x020:
0x022:
0x024:
0x026:
0x028:
0x030:
0x032:
0x034:
0x036:
0x038:
0x040:
...
0x080:
lda,c 5
push,r a
lda,c 7
push,r a
call 0x016
sta 0x080
inc,r sp,2
jmp 0x040
push,r fp
ldr fp,sp
dec,r sp,1
lda,c 0
sta,ri fp,-1
lda,ri fp,2
add,ri fp,3
sta,ri fp,-1
lda,ri fp,-1
ldr sp,fp
pop,r fp
ret
.end
...
0
It is eventually a good idea to make use of a linked list either after the above steps or already from step 3 onwards. Depending on your implementation the contents of the linked list could be made up by a structure as follows where every structure contains one line:
struct cpuinst {
unsigned int breakpoint; // 1 ... breakpoint is active at line; 0 ... breakpoint is inactive at line
unsigned int addr; // the address, i.e. 0x000 ... 0x1FF
unsigned char mnem[5]; // the mnemonic of the instruction, e.g. lda ... load accumulator
unsigned char addrm[3]; // the addressing mode, e.g. ri ... register indirect
unsigned char op1[20]; // the first operand
unsigned char op2[20]; // the second operand
struct cpuinst *pNext; // pointer to the next list element
};
The final program structure may now look something similar to the following figure.
So finally, having pre-processed and prepared the assembly file you are now up to actually start the simulator. After program invocation and having constructed the above list, the program halts before the first instruction. In an endless-loop it will now await directives from the user as shown in the first listing above. For example, a typical user interaction could look like:
bs 0x04
r
dr
s
dr
s
dr
dm
q
The first user command entered at the prompt (bs 0x04) will set a breakpoint at line 0x10. After having read this line from the user the program will traverse the linked list from the start up to the list holding address number 0x10; there it will set the break field to 1.
Next the user issued a run command (r); The program will now read list by list by always checking whether a breakpoint in the list is set. When a breakpoint is set the execution of insctructions is halted, otherwise, the command and operands are read and executed as detailed in the Instruction Set of the Model CPU document. In the above example the following steps are performed:
Check the breakpoint variable on the first list; since it is not set read the command and operands and execute the instruction. Here the command is load the addressing mode is c (constant address) and the operand1 is 5. Execution: accu = 5; flags are left unmodified; IAR (initial calue = 0x00) is incremented by 2
Read the next list; check the breakpoint variable; since it is not set read the command and operands and execute the instruction. Here the command is push the addressing mode is r (register address) and the operand1 is register a (=accumulator). Execution: the stack pointer (initial value = 0x200) is decremented by 2; the value of the accumulator is stored at the location where the stack pointer now points too (0x1FE); the flags are left unmodified; IAR is incremented by 2 once more, hence, it's value becomes 0x04
Read the next list; check the breakpoint variable; since the breakpoint is set stop the execution
The next issued command is dr ... the contents of all relevant regsiters are dumped/output to the screen.
Afterwards a step instruction s was given ... the next list is fetched the command and operands are read and executed. (Note: when a step command is issued the breakpoint variable is of no relevance/ignored.) Execution: accu = 7; flags are left unmodified; IAR is incremented by 2 -> now 0x06
The next issued command is dr ... the contents of all relevant regsiters are dumped/output to the screen.
Afterwards a step instruction s was given ... the next list is fetched the command and operands are read and executed. (Note: when a step command is issued the breakpoint variable is of no relevance/ignored.) Execution: the stack pointer is decremented by 2 -> now 0x1FC; the value of the accumulator is stored at the location where the stack pointer now points too (0x1FC); the flags are left unmodified; IAR is incremented by 2 -> now 0x08
The next issued command is dr ... the contents of all relevant regsiters are dumped/output to the screen.
The next issued command is dm ... the contents of the memory is dumped/output to the screen in a compact form.
The final command q terminates the program.
When the optional file logging mechanism is implemented all this information (and maybe even more) is written to a log file as well.
thanks
hellboyy