《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

989 lines
36 KiB

  1. #! /usr/bin/env python
  2. import sys
  3. import time
  4. import random
  5. from optparse import OptionParser
  6. #
  7. # HELPER
  8. #
  9. def dospace(howmuch):
  10. for i in range(howmuch):
  11. print '%24s' % ' ',
  12. # useful instead of assert
  13. def zassert(cond, str):
  14. if cond == False:
  15. print 'ABORT::', str
  16. exit(1)
  17. return
  18. class cpu:
  19. #
  20. # INIT: how much memory?
  21. #
  22. def __init__(self, memory, memtrace, regtrace, cctrace, compute, verbose):
  23. #
  24. # CONSTANTS
  25. #
  26. # conditions
  27. self.COND_GT = 0
  28. self.COND_GTE = 1
  29. self.COND_LT = 2
  30. self.COND_LTE = 3
  31. self.COND_EQ = 4
  32. self.COND_NEQ = 5
  33. # registers in system
  34. self.REG_ZERO = 0
  35. self.REG_AX = 1
  36. self.REG_BX = 2
  37. self.REG_CX = 3
  38. self.REG_DX = 4
  39. self.REG_SP = 5
  40. self.REG_BP = 6
  41. # system memory: in KB
  42. self.max_memory = memory * 1024
  43. # which memory addrs and registers to trace?
  44. self.memtrace = memtrace
  45. self.regtrace = regtrace
  46. self.cctrace = cctrace
  47. self.compute = compute
  48. self.verbose = verbose
  49. self.PC = 0
  50. self.registers = {}
  51. self.conditions = {}
  52. self.labels = {}
  53. self.vars = {}
  54. self.memory = {}
  55. self.pmemory = {} # for printable version of what's in memory (instructions)
  56. self.condlist = [self.COND_GTE, self.COND_GT, self.COND_LTE, self.COND_LT, self.COND_NEQ, self.COND_EQ]
  57. self.regnums = [self.REG_ZERO, self.REG_AX, self.REG_BX, self.REG_CX, self.REG_DX, self.REG_SP, self.REG_BP]
  58. self.regnames = {}
  59. self.regnames['zero'] = self.REG_ZERO # hidden zero-valued register
  60. self.regnames['ax'] = self.REG_AX
  61. self.regnames['bx'] = self.REG_BX
  62. self.regnames['cx'] = self.REG_CX
  63. self.regnames['dx'] = self.REG_DX
  64. self.regnames['sp'] = self.REG_SP
  65. self.regnames['bp'] = self.REG_BP
  66. tmplist = []
  67. for r in self.regtrace:
  68. zassert(r in self.regnames, 'Register %s cannot be traced because it does not exist' % r)
  69. tmplist.append(self.regnames[r])
  70. self.regtrace = tmplist
  71. self.init_memory()
  72. self.init_registers()
  73. self.init_condition_codes()
  74. #
  75. # BEFORE MACHINE RUNS
  76. #
  77. def init_condition_codes(self):
  78. for c in self.condlist:
  79. self.conditions[c] = False
  80. def init_memory(self):
  81. for i in range(self.max_memory):
  82. self.memory[i] = 0
  83. def init_registers(self):
  84. for i in self.regnums:
  85. self.registers[i] = 0
  86. def dump_memory(self):
  87. print 'MEMORY DUMP'
  88. for i in range(self.max_memory):
  89. if i not in self.pmemory and i in self.memory and self.memory[i] != 0:
  90. print ' m[%d]' % i, self.memory[i]
  91. #
  92. # INFORMING ABOUT THE HARDWARE
  93. #
  94. def get_regnum(self, name):
  95. assert(name in self.regnames)
  96. return self.regnames[name]
  97. def get_regname(self, num):
  98. assert(num in self.regnums)
  99. for rname in self.regnames:
  100. if self.regnames[rname] == num:
  101. return rname
  102. return ''
  103. def get_regnums(self):
  104. return self.regnums
  105. def get_condlist(self):
  106. return self.condlist
  107. def get_reg(self, reg):
  108. assert(reg in self.regnums)
  109. return self.registers[reg]
  110. def get_cond(self, cond):
  111. assert(cond in self.condlist)
  112. return self.conditions[cond]
  113. def get_pc(self):
  114. return self.PC
  115. def set_reg(self, reg, value):
  116. assert(reg in self.regnums)
  117. self.registers[reg] = value
  118. def set_cond(self, cond, value):
  119. assert(cond in self.condlist)
  120. self.conditions[cond] = value
  121. def set_pc(self, pc):
  122. self.PC = pc
  123. #
  124. # INSTRUCTIONS
  125. #
  126. def halt(self):
  127. return -1
  128. def iyield(self):
  129. return -2
  130. def nop(self):
  131. return 0
  132. def rdump(self):
  133. print 'REGISTERS::',
  134. print 'ax:', self.registers[self.REG_AX],
  135. print 'bx:', self.registers[self.REG_BX],
  136. print 'cx:', self.registers[self.REG_CX],
  137. print 'dx:', self.registers[self.REG_DX],
  138. def mdump(self, index):
  139. print 'm[%d] ' % index, self.memory[index]
  140. def move_i_to_r(self, src, dst):
  141. self.registers[dst] = src
  142. return 0
  143. # memory: value, register, register
  144. def move_i_to_m(self, src, value, reg1, reg2):
  145. tmp = value + self.registers[reg1] + self.registers[reg2]
  146. self.memory[tmp] = src
  147. return 0
  148. def move_m_to_r(self, value, reg1, reg2, dst):
  149. tmp = value + self.registers[reg1] + self.registers[reg2]
  150. # print 'doing mov', 'val:', value, 'r1:', self.get_regname(reg1), self.registers[reg1], 'r2:', self.get_regname(reg2), self.registers[reg2], 'dst', self.get_regname(dst), 'tmp', tmp, 'reg[dst]', self.registers[dst], 'mem', self.memory[tmp]
  151. self.registers[dst] = self.memory[tmp]
  152. def move_r_to_m(self, src, value, reg1, reg2):
  153. tmp = value + self.registers[reg1] + self.registers[reg2]
  154. self.memory[tmp] = self.registers[src]
  155. return 0
  156. def move_r_to_r(self, src, dst):
  157. self.registers[dst] = self.registers[src]
  158. return 0
  159. def add_i_to_r(self, src, dst):
  160. self.registers[dst] += src
  161. return 0
  162. def add_r_to_r(self, src, dst):
  163. self.registers[dst] += self.registers[src]
  164. return 0
  165. def sub_i_to_r(self, src, dst):
  166. self.registers[dst] -= src
  167. return 0
  168. def sub_r_to_r(self, src, dst):
  169. self.registers[dst] -= self.registers[src]
  170. return 0
  171. #
  172. # SUPPORT FOR LOCKS
  173. #
  174. def atomic_exchange(self, src, value, reg1, reg2):
  175. tmp = value + self.registers[reg1] + self.registers[reg2]
  176. old = self.memory[tmp]
  177. self.memory[tmp] = self.registers[src]
  178. self.registers[src] = old
  179. return 0
  180. def fetchadd(self, src, value, reg1, reg2):
  181. tmp = value + self.registers[reg1] + self.registers[reg2]
  182. old = self.memory[tmp]
  183. self.memory[tmp] = self.memory[tmp] + self.registers[src]
  184. self.registers[src] = old
  185. #
  186. # TEST for conditions
  187. #
  188. def test_all(self, src, dst):
  189. self.init_condition_codes()
  190. if dst > src:
  191. self.conditions[self.COND_GT] = True
  192. if dst >= src:
  193. self.conditions[self.COND_GTE] = True
  194. if dst < src:
  195. self.conditions[self.COND_LT] = True
  196. if dst <= src:
  197. self.conditions[self.COND_LTE] = True
  198. if dst == src:
  199. self.conditions[self.COND_EQ] = True
  200. if dst != src:
  201. self.conditions[self.COND_NEQ] = True
  202. return 0
  203. def test_i_r(self, src, dst):
  204. self.init_condition_codes()
  205. return self.test_all(src, self.registers[dst])
  206. def test_r_i(self, src, dst):
  207. self.init_condition_codes()
  208. return self.test_all(self.registers[src], dst)
  209. def test_r_r(self, src, dst):
  210. self.init_condition_codes()
  211. return self.test_all(self.registers[src], self.registers[dst])
  212. #
  213. # JUMPS
  214. #
  215. def jump(self, targ):
  216. self.PC = targ
  217. return 0
  218. def jump_notequal(self, targ):
  219. if self.conditions[self.COND_NEQ] == True:
  220. self.PC = targ
  221. return 0
  222. def jump_equal(self, targ):
  223. if self.conditions[self.COND_EQ] == True:
  224. self.PC = targ
  225. return 0
  226. def jump_lessthan(self, targ):
  227. if self.conditions[self.COND_LT] == True:
  228. self.PC = targ
  229. return 0
  230. def jump_lessthanorequal(self, targ):
  231. if self.conditions[self.COND_LTE] == True:
  232. self.PC = targ
  233. return 0
  234. def jump_greaterthan(self, targ):
  235. if self.conditions[self.COND_GT] == True:
  236. self.PC = targ
  237. return 0
  238. def jump_greaterthanorequal(self, targ):
  239. if self.conditions[self.COND_GTE] == True:
  240. self.PC = targ
  241. return 0
  242. #
  243. # CALL and RETURN
  244. #
  245. def call(self, targ):
  246. self.registers[self.REG_SP] -= 4
  247. self.memory[self.registers[self.REG_SP]] = self.PC
  248. self.PC = targ
  249. def ret(self):
  250. self.PC = self.memory[self.registers[self.REG_SP]]
  251. self.registers[self.REG_SP] += 4
  252. #
  253. # STACK and related
  254. #
  255. def push_r(self, reg):
  256. self.registers[self.REG_SP] -= 4
  257. self.memory[self.registers[self.REG_SP]] = self.registers[reg]
  258. return 0
  259. def push_m(self, value, reg1, reg2):
  260. # print 'push_m', value, reg1, reg2
  261. self.registers[self.REG_SP] -= 4
  262. tmp = value + self.registers[reg1] + self.registers[reg2]
  263. # push address onto stack, not memory value itself
  264. self.memory[self.registers[self.REG_SP]] = tmp
  265. return 0
  266. def pop(self):
  267. self.registers[self.REG_SP] += 4
  268. def pop_r(self, dst):
  269. self.registers[dst] = self.registers[self.REG_SP]
  270. self.registers[self.REG_SP] += 4
  271. #
  272. # HELPER func for getarg
  273. #
  274. def register_translate(self, r):
  275. if r in self.regnames:
  276. return self.regnames[r]
  277. zassert(False, 'Register %s is not a valid register' % r)
  278. return
  279. #
  280. # HELPER in parsing mov (quite primitive) and other ops
  281. # returns: (value, type)
  282. # where type is (TYPE_REGISTER, TYPE_IMMEDIATE, TYPE_MEMORY)
  283. #
  284. # FORMATS
  285. # %ax - register
  286. # $10 - immediate
  287. # 10 - direct memory
  288. # 10(%ax) - memory + reg indirect
  289. # 10(%ax,%bx) - memory + 2 reg indirect
  290. # 10(%ax,%bx,4) - XXX (not handled)
  291. #
  292. def getarg(self, arg):
  293. tmp1 = arg.replace(',', '')
  294. tmp = tmp1.replace(' \t', '')
  295. if tmp[0] == '$':
  296. zassert(len(tmp) == 2, 'correct form is $number (not %s)' % tmp)
  297. value = tmp.split('$')[1]
  298. zassert(value.isdigit(), 'value [%s] must be a digit' % value)
  299. return int(value), 'TYPE_IMMEDIATE'
  300. elif tmp[0] == '%':
  301. register = tmp.split('%')[1]
  302. return self.register_translate(register), 'TYPE_REGISTER'
  303. elif tmp[0] == '(':
  304. register = tmp.split('(')[1].split(')')[0].split('%')[1]
  305. return '%d,%d,%d' % (0, self.register_translate(register), self.register_translate('zero')), 'TYPE_MEMORY'
  306. elif tmp[0] == '.':
  307. targ = tmp
  308. return targ, 'TYPE_LABEL'
  309. elif tmp[0].isalpha() and not tmp[0].isdigit():
  310. zassert(tmp in self.vars, 'Variable %s is not declared' % tmp)
  311. # print '%d,%d,%d' % (self.vars[tmp], self.register_translate('zero'), self.register_translate('zero')), 'TYPE_MEMORY'
  312. return '%d,%d,%d' % (self.vars[tmp], self.register_translate('zero'), self.register_translate('zero')), 'TYPE_MEMORY'
  313. elif tmp[0].isdigit() or tmp[0] == '-':
  314. # MOST GENERAL CASE: number(reg,reg) or number(reg)
  315. # we ignore the common x86 number(reg,reg,constant) for now
  316. neg = 1
  317. if tmp[0] == '-':
  318. tmp = tmp[1:]
  319. neg = -1
  320. s = tmp.split('(')
  321. if len(s) == 1:
  322. value = neg * int(tmp)
  323. # print '%d,%d,%d' % (int(value), self.register_translate('zero'), self.register_translate('zero')), 'TYPE_MEMORY'
  324. return '%d,%d,%d' % (int(value), self.register_translate('zero'), self.register_translate('zero')), 'TYPE_MEMORY'
  325. elif len(s) == 2:
  326. value = neg * int(s[0])
  327. t = s[1].split(')')[0].split(',')
  328. if len(t) == 1:
  329. register = t[0].split('%')[1]
  330. # print '%d,%d,%d' % (int(value), self.register_translate(register), self.register_translate('zero')), 'TYPE_MEMORY'
  331. return '%d,%d,%d' % (int(value), self.register_translate(register), self.register_translate('zero')), 'TYPE_MEMORY'
  332. elif len(t) == 2:
  333. register1 = t[0].split('%')[1]
  334. register2 = t[1].split('%')[1]
  335. # print '%d,%d,%d' % (int(value), self.register_translate(register1), self.register_translate(register2)), 'TYPE_MEMORY'
  336. return '%d,%d,%d' % (int(value), self.register_translate(register1), self.register_translate(register2)), 'TYPE_MEMORY'
  337. else:
  338. print 'mov: bad argument [%s]' % tmp
  339. exit(1)
  340. return
  341. zassert(True, 'mov: bad argument [%s]' % arg)
  342. return
  343. #
  344. # LOAD a program into memory
  345. # make it ready to execute
  346. #
  347. def load(self, infile, loadaddr):
  348. pc = int(loadaddr)
  349. fd = open(infile)
  350. bpc = loadaddr
  351. data = 100
  352. for line in fd:
  353. cline = line.rstrip()
  354. # print 'PASS 1', cline
  355. # remove everything after the comment marker
  356. ctmp = cline.split('#')
  357. assert(len(ctmp) == 1 or len(ctmp) == 2)
  358. if len(ctmp) == 2:
  359. cline = ctmp[0]
  360. # remove empty lines, and split line by spaces
  361. tmp = cline.split()
  362. if len(tmp) == 0:
  363. continue
  364. # only pay attention to labels and variables
  365. if tmp[0] == '.var':
  366. assert(len(tmp) == 2)
  367. assert(tmp[0] not in self.vars)
  368. self.vars[tmp[1]] = data
  369. data += 4
  370. zassert(data < bpc, 'Load address overrun by static data')
  371. if self.verbose: print 'ASSIGN VAR', tmp[0], "-->", tmp[1], self.vars[tmp[1]]
  372. elif tmp[0][0] == '.':
  373. assert(len(tmp) == 1)
  374. self.labels[tmp[0]] = int(pc)
  375. if self.verbose: print 'ASSIGN LABEL', tmp[0], "-->", pc
  376. else:
  377. pc += 1
  378. fd.close()
  379. if self.verbose: print ''
  380. # second pass: do everything else
  381. pc = int(loadaddr)
  382. fd = open(infile)
  383. for line in fd:
  384. cline = line.rstrip()
  385. # print 'PASS 2', cline
  386. # remove everything after the comment marker
  387. ctmp = cline.split('#')
  388. assert(len(ctmp) == 1 or len(ctmp) == 2)
  389. if len(ctmp) == 2:
  390. cline = ctmp[0]
  391. # remove empty lines, and split line by spaces
  392. tmp = cline.split()
  393. if len(tmp) == 0:
  394. continue
  395. # skip labels: all else must be instructions
  396. if cline[0] != '.':
  397. tmp = cline.split(None, 1)
  398. opcode = tmp[0]
  399. self.pmemory[pc] = cline.strip()
  400. # MAIN OPCODE LOOP
  401. if opcode == 'mov':
  402. rtmp = tmp[1].split(',', 1)
  403. zassert(len(tmp) == 2 and len(rtmp) == 2, 'mov: needs two args, separated by commas [%s]' % cline)
  404. arg1 = rtmp[0].strip()
  405. arg2 = rtmp[1].strip()
  406. (src, stype) = self.getarg(arg1)
  407. (dst, dtype) = self.getarg(arg2)
  408. # print 'MOV', src, stype, dst, dtype
  409. if stype == 'TYPE_MEMORY' and dtype == 'TYPE_MEMORY':
  410. print 'bad mov: two memory arguments'
  411. exit(1)
  412. elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_IMMEDIATE':
  413. print 'bad mov: two immediate arguments'
  414. exit(1)
  415. elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
  416. self.memory[pc] = 'self.move_i_to_r(%d, %d)' % (int(src), dst)
  417. elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
  418. self.memory[pc] = 'self.move_i_to_r(%d, %d)' % (int(src), dst)
  419. elif stype == 'TYPE_MEMORY' and dtype == 'TYPE_REGISTER':
  420. tmp = src.split(',')
  421. assert(len(tmp) == 3)
  422. self.memory[pc] = 'self.move_m_to_r(%d, %d, %d, %d)' % (int(tmp[0]), int(tmp[1]), int(tmp[2]), dst)
  423. elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_MEMORY':
  424. tmp = dst.split(',')
  425. assert(len(tmp) == 3)
  426. self.memory[pc] = 'self.move_r_to_m(%d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2]))
  427. elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER':
  428. self.memory[pc] = 'self.move_r_to_r(%d, %d)' % (src, dst)
  429. elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_MEMORY':
  430. tmp = dst.split(',')
  431. assert(len(tmp) == 3)
  432. self.memory[pc] = 'self.move_i_to_m(%d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2]))
  433. else:
  434. zassert(False, 'malformed mov instruction')
  435. elif opcode == 'pop':
  436. if len(tmp) == 1:
  437. self.memory[pc] = 'self.pop()'
  438. elif len(tmp) == 2:
  439. arg = tmp[1].strip()
  440. (dst, dtype) = self.getarg(arg)
  441. zassert(dtype == 'TYPE_REGISTER', 'Can only pop into a register')
  442. self.memory[pc] = 'self.pop_r(%d)' % dst
  443. else:
  444. zassert(False, 'pop instruction must take zero/one args')
  445. elif opcode == 'push':
  446. (src, stype) = self.getarg(tmp[1].strip())
  447. if stype == 'TYPE_REGISTER':
  448. self.memory[pc] = 'self.push_r(%d)' % (int(src))
  449. elif stype == 'TYPE_MEMORY':
  450. tmp = src.split(',')
  451. assert(len(tmp) == 3)
  452. self.memory[pc] = 'self.push_m(%d,%d,%d)' % (int(tmp[0]), int(tmp[1]), int(tmp[2]))
  453. else:
  454. zassert(False, 'Cannot push anything but registers')
  455. elif opcode == 'call':
  456. (targ, ttype) = self.getarg(tmp[1].strip())
  457. if ttype == 'TYPE_LABEL':
  458. self.memory[pc] = 'self.call(%d)' % (int(self.labels[targ]))
  459. else:
  460. zassert(False, 'Cannot call anything but a label')
  461. elif opcode == 'ret':
  462. assert(len(tmp) == 1)
  463. self.memory[pc] = 'self.ret()'
  464. elif opcode == 'add':
  465. rtmp = tmp[1].split(',', 1)
  466. zassert(len(tmp) == 2 and len(rtmp) == 2, 'add: needs two args, separated by commas [%s]' % cline)
  467. arg1 = rtmp[0].strip()
  468. arg2 = rtmp[1].strip()
  469. (src, stype) = self.getarg(arg1)
  470. (dst, dtype) = self.getarg(arg2)
  471. if stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
  472. self.memory[pc] = 'self.add_i_to_r(%d, %d)' % (int(src), dst)
  473. elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER':
  474. self.memory[pc] = 'self.add_r_to_r(%d, %d)' % (int(src), dst)
  475. else:
  476. zassert(False, 'malformed usage of add instruction')
  477. elif opcode == 'sub':
  478. rtmp = tmp[1].split(',', 1)
  479. zassert(len(tmp) == 2 and len(rtmp) == 2, 'sub: needs two args, separated by commas [%s]' % cline)
  480. arg1 = rtmp[0].strip()
  481. arg2 = rtmp[1].strip()
  482. (src, stype) = self.getarg(arg1)
  483. (dst, dtype) = self.getarg(arg2)
  484. if stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
  485. self.memory[pc] = 'self.sub_i_to_r(%d, %d)' % (int(src), dst)
  486. elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER':
  487. self.memory[pc] = 'self.sub_r_to_r(%d, %d)' % (int(src), dst)
  488. else:
  489. zassert(False, 'malformed usage of sub instruction')
  490. elif opcode == 'fetchadd':
  491. rtmp = tmp[1].split(',', 1)
  492. zassert(len(tmp) == 2 and len(rtmp) == 2, 'fetchadd: needs two args, separated by commas [%s]' % cline)
  493. arg1 = rtmp[0].strip()
  494. arg2 = rtmp[1].strip()
  495. (src, stype) = self.getarg(arg1)
  496. (dst, dtype) = self.getarg(arg2)
  497. tmp = dst.split(',')
  498. assert(len(tmp) == 3)
  499. if stype == 'TYPE_REGISTER' and dtype == 'TYPE_MEMORY':
  500. self.memory[pc] = 'self.fetchadd(%d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2]))
  501. else:
  502. zassert(False, 'poorly specified fetch and add')
  503. elif opcode == 'xchg':
  504. rtmp = tmp[1].split(',', 1)
  505. zassert(len(tmp) == 2 and len(rtmp) == 2, 'xchg: needs two args, separated by commas [%s]' % cline)
  506. arg1 = rtmp[0].strip()
  507. arg2 = rtmp[1].strip()
  508. (src, stype) = self.getarg(arg1)
  509. (dst, dtype) = self.getarg(arg2)
  510. tmp = dst.split(',')
  511. assert(len(tmp) == 3)
  512. if stype == 'TYPE_REGISTER' and dtype == 'TYPE_MEMORY':
  513. self.memory[pc] = 'self.atomic_exchange(%d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2]))
  514. else:
  515. zassert(False, 'poorly specified atomic exchange')
  516. elif opcode == 'test':
  517. rtmp = tmp[1].split(',', 1)
  518. zassert(len(tmp) == 2 and len(rtmp) == 2, 'test: needs two args, separated by commas [%s]' % cline)
  519. arg1 = rtmp[0].strip()
  520. arg2 = rtmp[1].strip()
  521. (src, stype) = self.getarg(arg1)
  522. (dst, dtype) = self.getarg(arg2)
  523. if stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
  524. self.memory[pc] = 'self.test_i_r(%d, %d)' % (int(src), dst)
  525. elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER':
  526. self.memory[pc] = 'self.test_r_r(%d, %d)' % (int(src), dst)
  527. elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_IMMEDIATE':
  528. self.memory[pc] = 'self.test_r_i(%d, %d)' % (int(src), dst)
  529. else:
  530. zassert(False, 'malformed usage of test instruction')
  531. elif opcode == 'j':
  532. (targ, ttype) = self.getarg(tmp[1].strip())
  533. zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
  534. self.memory[pc] = 'self.jump(%d)' % int(self.labels[targ])
  535. elif opcode == 'jne':
  536. (targ, ttype) = self.getarg(tmp[1].strip())
  537. zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
  538. self.memory[pc] = 'self.jump_notequal(%d)' % int(self.labels[targ])
  539. elif opcode == 'je':
  540. (targ, ttype) = self.getarg(tmp[1].strip())
  541. zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
  542. self.memory[pc] = 'self.jump_equal(%d)' % self.labels[targ]
  543. elif opcode == 'jlt':
  544. (targ, ttype) = self.getarg(tmp[1].strip())
  545. zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
  546. self.memory[pc] = 'self.jump_lessthan(%d)' % int(self.labels[targ])
  547. elif opcode == 'jlte':
  548. (targ, ttype) = self.getarg(tmp[1].strip())
  549. zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
  550. self.memory[pc] = 'self.jump_lessthanorequal(%s)' % self.labels[targ]
  551. elif opcode == 'jgt':
  552. (targ, ttype) = self.getarg(tmp[1].strip())
  553. zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
  554. self.memory[pc] = 'self.jump_greaterthan(%d)' % int(self.labels[targ])
  555. elif opcode == 'jgte':
  556. (targ, ttype) = self.getarg(tmp[1].strip())
  557. zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
  558. self.memory[pc] = 'self.jump_greaterthanorequal(%s)' % self.labels[targ]
  559. elif opcode == 'nop':
  560. self.memory[pc] = 'self.nop()'
  561. elif opcode == 'halt':
  562. self.memory[pc] = 'self.halt()'
  563. elif opcode == 'yield':
  564. self.memory[pc] = 'self.iyield()'
  565. elif opcode == 'rdump':
  566. self.memory[pc] = 'self.rdump()'
  567. elif opcode == 'mdump':
  568. self.memory[pc] = 'self.mdump(%s)' % tmp[1]
  569. else:
  570. print 'illegal opcode: ', opcode
  571. exit(1)
  572. if self.verbose: print 'pc:%d LOADING %20s --> %s' % (pc, self.pmemory[pc], self.memory[pc])
  573. # INCREMENT PC for loader
  574. pc += 1
  575. # END: loop over file
  576. fd.close()
  577. if self.verbose: print ''
  578. return
  579. # END: load
  580. def print_headers(self, procs):
  581. # print some headers
  582. if len(self.memtrace) > 0:
  583. for m in self.memtrace:
  584. if m[0].isdigit():
  585. print '%5d' % int(m),
  586. else:
  587. zassert(m in self.vars, 'Traced variable %s not declared' % m)
  588. print '%5s' % m,
  589. print ' ',
  590. if len(self.regtrace) > 0:
  591. for r in self.regtrace:
  592. print '%5s' % self.get_regname(r),
  593. print ' ',
  594. if cctrace == True:
  595. print '>= > <= < != ==',
  596. # and per thread
  597. for i in range(procs.getnum()):
  598. print ' Thread %d ' % i,
  599. print ''
  600. return
  601. def print_trace(self, newline):
  602. if len(self.memtrace) > 0:
  603. for m in self.memtrace:
  604. if self.compute:
  605. if m[0].isdigit():
  606. print '%5d' % self.memory[int(m)],
  607. else:
  608. zassert(m in self.vars, 'Traced variable %s not declared' % m)
  609. print '%5d' % self.memory[self.vars[m]],
  610. else:
  611. print '%5s' % '?',
  612. print ' ',
  613. if len(self.regtrace) > 0:
  614. for r in self.regtrace:
  615. if self.compute:
  616. print '%5d' % self.registers[r],
  617. else:
  618. print '%5s' % '?',
  619. print ' ',
  620. if cctrace == True:
  621. for c in self.condlist:
  622. if self.compute:
  623. if self.conditions[c]:
  624. print '1 ',
  625. else:
  626. print '0 ',
  627. else:
  628. print '? ',
  629. if (len(self.memtrace) > 0 or len(self.regtrace) > 0 or cctrace == True) and newline == True:
  630. print ''
  631. return
  632. def setint(self, intfreq, intrand):
  633. if intrand == False:
  634. return intfreq
  635. return int(random.random() * intfreq) + 1
  636. def run(self, procs, intfreq, intrand):
  637. # hw init: cc's, interrupt frequency, etc.
  638. interrupt = self.setint(intfreq, intrand)
  639. icount = 0
  640. self.print_headers(procs)
  641. self.print_trace(True)
  642. while True:
  643. # need thread ID of current process
  644. tid = procs.getcurr().gettid()
  645. # FETCH
  646. prevPC = self.PC
  647. instruction = self.memory[self.PC]
  648. self.PC += 1
  649. # DECODE and EXECUTE
  650. # key: self.PC may be changed during eval; thus MUST be incremented BEFORE eval
  651. rc = eval(instruction)
  652. # tracing details: ALWAYS AFTER EXECUTION OF INSTRUCTION
  653. self.print_trace(False)
  654. # output: thread-proportional spacing followed by PC and instruction
  655. dospace(tid)
  656. print prevPC, self.pmemory[prevPC]
  657. icount += 1
  658. # halt instruction issued
  659. if rc == -1:
  660. procs.done()
  661. if procs.numdone() == procs.getnum():
  662. return icount
  663. procs.next()
  664. procs.restore()
  665. self.print_trace(False)
  666. for i in range(procs.getnum()):
  667. print '----- Halt;Switch ----- ',
  668. print ''
  669. # do interrupt processing
  670. interrupt -= 1
  671. if interrupt == 0 or rc == -2:
  672. interrupt = self.setint(intfreq, intrand)
  673. procs.save()
  674. procs.next()
  675. procs.restore()
  676. self.print_trace(False)
  677. for i in range(procs.getnum()):
  678. print '------ Interrupt ------ ',
  679. print ''
  680. # END: while
  681. return
  682. #
  683. # END: class cpu
  684. #
  685. #
  686. # PROCESS LIST class
  687. #
  688. class proclist:
  689. def __init__(self):
  690. self.plist = []
  691. self.curr = 0
  692. self.active = 0
  693. def done(self):
  694. self.plist[self.curr].setdone()
  695. self.active -= 1
  696. def numdone(self):
  697. return len(self.plist) - self.active
  698. def getnum(self):
  699. return len(self.plist)
  700. def add(self, p):
  701. self.active += 1
  702. self.plist.append(p)
  703. def getcurr(self):
  704. return self.plist[self.curr]
  705. def save(self):
  706. self.plist[self.curr].save()
  707. def restore(self):
  708. self.plist[self.curr].restore()
  709. def next(self):
  710. for i in range(self.curr+1, len(self.plist)):
  711. if self.plist[i].isdone() == False:
  712. self.curr = i
  713. return
  714. for i in range(0, self.curr+1):
  715. if self.plist[i].isdone() == False:
  716. self.curr = i
  717. return
  718. #
  719. # PROCESS class
  720. #
  721. class process:
  722. def __init__(self, cpu, tid, pc, stackbottom, reginit):
  723. self.cpu = cpu # object reference
  724. self.tid = tid
  725. self.pc = pc
  726. self.regs = {}
  727. self.cc = {}
  728. self.done = False
  729. self.stack = stackbottom
  730. # init regs: all 0 or specially set to something
  731. for r in self.cpu.get_regnums():
  732. self.regs[r] = 0
  733. if reginit != '':
  734. # form: ax=1,bx=2 (for some subset of registers)
  735. for r in reginit.split(':'):
  736. tmp = r.split('=')
  737. assert(len(tmp) == 2)
  738. self.regs[self.cpu.get_regnum(tmp[0])] = int(tmp[1])
  739. # init CCs
  740. for c in self.cpu.get_condlist():
  741. self.cc[c] = False
  742. # stack
  743. self.regs[self.cpu.get_regnum('sp')] = stackbottom
  744. # print 'REG', self.cpu.get_regnum('sp'), self.regs[self.cpu.get_regnum('sp')]
  745. return
  746. def gettid(self):
  747. return self.tid
  748. def save(self):
  749. self.pc = self.cpu.get_pc()
  750. for c in self.cpu.get_condlist():
  751. self.cc[c] = self.cpu.get_cond(c)
  752. for r in self.cpu.get_regnums():
  753. self.regs[r] = self.cpu.get_reg(r)
  754. def restore(self):
  755. self.cpu.set_pc(self.pc)
  756. for c in self.cpu.get_condlist():
  757. self.cpu.set_cond(c, self.cc[c])
  758. for r in self.cpu.get_regnums():
  759. self.cpu.set_reg(r, self.regs[r])
  760. def setdone(self):
  761. self.done = True
  762. def isdone(self):
  763. return self.done == True
  764. #
  765. # main program
  766. #
  767. parser = OptionParser()
  768. parser.add_option('-s', '--seed', default=0, help='the random seed', action='store', type='int', dest='seed')
  769. parser.add_option('-t', '--threads', default=2, help='number of threads', action='store', type='int', dest='numthreads')
  770. parser.add_option('-p', '--program', default='', help='source program (in .s)', action='store', type='string', dest='progfile')
  771. parser.add_option('-i', '--interrupt', default=50, help='interrupt frequency', action='store', type='int', dest='intfreq')
  772. parser.add_option('-r', '--randints', default=False, help='if interrupts are random', action='store_true', dest='intrand')
  773. parser.add_option('-a', '--argv', default='',
  774. help='comma-separated per-thread args (e.g., ax=1,ax=2 sets thread 0 ax reg to 1 and thread 1 ax reg to 2); specify multiple regs per thread via colon-separated list (e.g., ax=1:bx=2,cx=3 sets thread 0 ax and bx and just cx for thread 1)',
  775. action='store', type='string', dest='argv')
  776. parser.add_option('-L', '--loadaddr', default=1000, help='address where to load code', action='store', type='int', dest='loadaddr')
  777. parser.add_option('-m', '--memsize', default=128, help='size of address space (KB)', action='store', type='int', dest='memsize')
  778. parser.add_option('-M', '--memtrace', default='', help='comma-separated list of addrs to trace (e.g., 20000,20001)', action='store',
  779. type='string', dest='memtrace')
  780. parser.add_option('-R', '--regtrace', default='', help='comma-separated list of regs to trace (e.g., ax,bx,cx,dx)', action='store',
  781. type='string', dest='regtrace')
  782. parser.add_option('-C', '--cctrace', default=False, help='should we trace condition codes', action='store_true', dest='cctrace')
  783. parser.add_option('-S', '--printstats',default=False, help='print some extra stats', action='store_true', dest='printstats')
  784. parser.add_option('-v', '--verbose', default=False, help='print some extra info', action='store_true', dest='verbose')
  785. parser.add_option('-c', '--compute', default=False, help='compute answers for me', action='store_true', dest='solve')
  786. (options, args) = parser.parse_args()
  787. print 'ARG seed', options.seed
  788. print 'ARG numthreads', options.numthreads
  789. print 'ARG program', options.progfile
  790. print 'ARG interrupt frequency', options.intfreq
  791. print 'ARG interrupt randomness',options.intrand
  792. print 'ARG argv', options.argv
  793. print 'ARG load address', options.loadaddr
  794. print 'ARG memsize', options.memsize
  795. print 'ARG memtrace', options.memtrace
  796. print 'ARG regtrace', options.regtrace
  797. print 'ARG cctrace', options.cctrace
  798. print 'ARG printstats', options.printstats
  799. print 'ARG verbose', options.verbose
  800. print ''
  801. seed = int(options.seed)
  802. numthreads = int(options.numthreads)
  803. intfreq = int(options.intfreq)
  804. zassert(intfreq > 0, 'Interrupt frequency must be greater than 0')
  805. intrand = int(options.intrand)
  806. progfile = options.progfile
  807. zassert(progfile != '', 'Program file must be specified')
  808. argv = options.argv.split(',')
  809. zassert(len(argv) == numthreads or len(argv) == 1, 'argv: must be one per-thread or just one set of values for all threads')
  810. loadaddr = options.loadaddr
  811. memsize = options.memsize
  812. memtrace = []
  813. if options.memtrace != '':
  814. for m in options.memtrace.split(','):
  815. memtrace.append(m)
  816. regtrace = []
  817. if options.regtrace != '':
  818. for r in options.regtrace.split(','):
  819. regtrace.append(r)
  820. cctrace = options.cctrace
  821. printstats = options.printstats
  822. verbose = options.verbose
  823. #
  824. # MAIN program
  825. #
  826. debug = False
  827. debug = False
  828. cpu = cpu(memsize, memtrace, regtrace, cctrace, options.solve, verbose)
  829. # load a program
  830. cpu.load(progfile, loadaddr)
  831. # process list
  832. procs = proclist()
  833. pid = 0
  834. stack = memsize * 1000
  835. for t in range(numthreads):
  836. if len(argv) > 1:
  837. arg = argv[pid]
  838. else:
  839. arg = argv[0]
  840. procs.add(process(cpu, pid, loadaddr, stack, arg))
  841. stack -= 1000
  842. pid += 1
  843. # get first one ready!
  844. procs.restore()
  845. # run it
  846. t1 = time.clock()
  847. ic = cpu.run(procs, intfreq, intrand)
  848. t2 = time.clock()
  849. if printstats:
  850. print ''
  851. print 'STATS:: Instructions %d' % ic
  852. print 'STATS:: Emulation Rate %.2f kinst/sec' % (float(ic) / float(t2 - t1) / 1000.0)
  853. # use this for profiling
  854. # import cProfile
  855. # cProfile.run('run()')