2023/05/23 - 12:53
Help session:
ASM file, assembler produces an XME file and a LIS file.
XME:
- executable file
- Contains S records
→ S0 : contains filename
→ s1: instructions and data
→ s9: starting address
⇒ typically put into the program counter
- Typical format: s0s then S1s then S9s
LIS
We are writing an emulator
- what does it do?
→ Emulating the CPU
→ Emulating Memory
→ NOt emulating devices (Yet?)
- In order to make it useful we have to write support software for it.
→ Loader
→ Loader takes the xme files and puts them into memory.
→ It can also set the program counter to the value in the S9 record.
→ If wedont put an end directive in, the default starting address is 0.
→ Couple things to note about the loader:
⇒ Always need an S record
• s[type][length][address] are present in every record
• what comes after depends on the typee
• 0: chars
• 1: data, instructions
• 9: whatever the PC gets
• at the end of all of them, theres a checksum
• don't read the data twice. only read it once, and send a diagnostic if the checksum fails.
⇒ Main()
⇒ initializations
⇒ call debugger
• debugger has options: load... go
• go calls CPU
◇ WHILE COND
▪ fetch
▪ decode
▪ execute
◇ END WHILE
⇒ Memory:
• 64 KiB
• 0000-FFFF
• what's the last value the PC can have in memory?
◇ FFFE
◇ because instructions have to start on an even byte location
◇ if it exceeds FFFF, you should wrap back around to address 0
◇ FFFE +2 = 0000 anyway
• Any register or memory lcoaiton change is a state change of the machine.
• An arithmetic operation can change the PSW, also a state change.
⇒ While emulating the machine, we also want to emulate memory. How?
• An array
• How will we define an array of 64 kibibytes?
• #define MEM_SIZE 1 << 16
• unsigned char memory[MEM_SIZE]
• we would like to access memory at the word level
• word memory only goes from 0 - 4FFF but maps into the same locations
• each word occupies 2 bytes
• #define WDMEMSZ 1<<15
• #define BMEMSZ 1 << 16
• short wmem[WDMEMSZ]
• We can make a union
◇ unions allow us to share memory between two structs/arrays/etc
◇ union mem{
▪ unsigned short wm[WDMEMSZ]
▪ unsigned char bm[BMEMSZ]
◇ }
◇ union mem memory
◇ wm and bm are fields inside the structure
◇ access like this: memory.wm[index], memory.bm[index]
• Accessing memory:
◇ we have to distingish between reading and writing
◇ also have to indicate whether its a word or byte
◇ also be given the equivalent of a memory address register or memory data register, and memory buffer register
• Larry suggests a function called Bus that would take (MAR, MDR, RW, W/B)
• ifwe are doing a write to memory, this would look like:
◇ WORD: mem.wm[MAR>>1] = MDR
◇ BYTE: mem.bm[MAR] = MDR ...&0xFF(if you want.. stops overflow)
• assume that MDR is a short.
• even if they're writing a byte it gets mapped to a short
• READ:
◇ WORD: MDR = mem.wm[MAR>>1]
◇ BYTE: MDR = mem.bm[MAR]
◇ this doesnt work because it only changes the local MDR
• WRITE:
◇ call Bus(Address, data, WRITE, w/b)
• READ:
◇ call Bus(Address, data, READ, w/b)
• These parameters are passed by value
• have to pass by reference: pass &data.
• bus( unsigned short MAR, unsigned short *MBR, ACCESS r/w, WORDBYTE w/b)
◇ pointer needs to be dereferenced.
◇ WRITE:
▪ WORD: mem.wm[MAR>>1] = *MDR
▪ BYTE: mem.bm[MAR] = *MDR ...&0xFF(if you want.. stops overflow)
◇ READ:
▪ WORD: &MDR = mem.wm[MAR>>1]
▪ BYTE: &MDR = mem.bm[MAR]
Regsiter file
- holds all the registers
- values of all registers
- registers go from R0-R7
- how do we set that up?
→ an array.
→ #define RFSZ 8
→ unsigned short regfile[RFSZ]
- Where do we get the register values?
→ each instruction
→ they all have fields
→ Least sig 3 bits are Destination
→ next 3 are SRC registers (or constant)
⇒ if we're talking about registers, the value will go from 0-7 which will let us access our array
⇒ bits 3-5 are listed as s/c s/c s/c
⇒ indicating they can be a source register or a constant indicator
⇒ not the value of the constant itself
⇒ bit 6 indicates whether the operation is WORD oR BYTE
⇒ bit 7 indicates whether the operation is REGISTER or CONSTANT
• 0 - REG
• 1 - CONS
→ Set up a 2d array that can index the registers and constants
→ how do we know which one to choose?
⇒ bit 7
⇒ if r/c is 0
• src gets regfile[s/c]
⇒ else
• src gets confile[s/c]
⇒ this is clunky and we should use a table
⇒ how will we define the data structure?
• it's a 2D array
• unsigned short Regfile[2][RFSZ] = {{0,0,0,0,0,0,0,0}{0,1,2,4,8,16,32,-1}}
• nothing stops us from overwriting the constants besides our own code.
⇒ how are we gonna use this
• ADD #2 R3
• R/C =1
• WB = 0
• SRC = 010
• DST = 011
• DST = DST + s/c
• DST = Regfile[0][DST] + Regfile[R/C][SRC]
- Want to minimize the number of times you touch data.
- Aim for table driven software. Index