《操作系统》的实验代码。
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

1186 行
44 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, printstats, headercount):
  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_EX = 5
  40. self.REG_FX = 6
  41. self.REG_SP = 7
  42. self.REG_BP = 8
  43. # system memory: in KB
  44. self.max_memory = memory * 1024
  45. # which memory addrs and registers to trace?
  46. self.memtrace = memtrace
  47. self.regtrace = regtrace
  48. self.cctrace = cctrace
  49. self.compute = compute
  50. self.verbose = verbose
  51. self.printstats = printstats
  52. self.headercount = headercount
  53. self.PC = 0
  54. self.registers = {}
  55. self.conditions = {}
  56. self.labels = {}
  57. self.vars = {}
  58. self.memory = {}
  59. self.pmemory = {} # for printable version of what's in memory (instructions)
  60. self.condlist = [self.COND_GTE, self.COND_GT, self.COND_LTE,
  61. self.COND_LT, self.COND_NEQ, self.COND_EQ]
  62. self.regnums = [self.REG_ZERO,
  63. self.REG_AX, self.REG_BX, self.REG_CX,
  64. self.REG_DX, self.REG_EX, self.REG_FX,
  65. self.REG_SP, self.REG_BP]
  66. self.regnames = {}
  67. self.regnames['zero'] = self.REG_ZERO # hidden zero-valued register
  68. self.regnames['ax'] = self.REG_AX
  69. self.regnames['bx'] = self.REG_BX
  70. self.regnames['cx'] = self.REG_CX
  71. self.regnames['dx'] = self.REG_DX
  72. self.regnames['ex'] = self.REG_EX
  73. self.regnames['fx'] = self.REG_FX
  74. self.regnames['sp'] = self.REG_SP
  75. self.regnames['bp'] = self.REG_BP
  76. tmplist = []
  77. for r in self.regtrace:
  78. zassert(r in self.regnames, 'Register %s cannot be traced because it does not exist' % r)
  79. tmplist.append(self.regnames[r])
  80. self.regtrace = tmplist
  81. self.init_memory()
  82. self.init_registers()
  83. self.init_condition_codes()
  84. #
  85. # BEFORE MACHINE RUNS
  86. #
  87. def init_condition_codes(self):
  88. for c in self.condlist:
  89. self.conditions[c] = False
  90. def init_memory(self):
  91. for i in range(self.max_memory):
  92. self.memory[i] = 0
  93. def init_registers(self):
  94. for i in self.regnums:
  95. self.registers[i] = 0
  96. def dump_memory(self):
  97. print 'MEMORY DUMP'
  98. for i in range(self.max_memory):
  99. if i not in self.pmemory and i in self.memory and self.memory[i] != 0:
  100. print ' m[%d]' % i, self.memory[i]
  101. #
  102. # INFORMING ABOUT THE HARDWARE
  103. #
  104. def get_regnum(self, name):
  105. assert(name in self.regnames)
  106. return self.regnames[name]
  107. def get_regname(self, num):
  108. assert(num in self.regnums)
  109. for rname in self.regnames:
  110. if self.regnames[rname] == num:
  111. return rname
  112. return ''
  113. def get_regnums(self):
  114. return self.regnums
  115. def get_condlist(self):
  116. return self.condlist
  117. def get_reg(self, reg):
  118. assert(reg in self.regnums)
  119. return self.registers[reg]
  120. def get_cond(self, cond):
  121. assert(cond in self.condlist)
  122. return self.conditions[cond]
  123. def get_pc(self):
  124. return self.PC
  125. def set_reg(self, reg, value):
  126. assert(reg in self.regnums)
  127. self.registers[reg] = value
  128. def set_cond(self, cond, value):
  129. assert(cond in self.condlist)
  130. self.conditions[cond] = value
  131. def set_pc(self, pc):
  132. self.PC = pc
  133. #
  134. # INSTRUCTIONS
  135. #
  136. def halt(self):
  137. return -1
  138. def iyield(self):
  139. return -2
  140. def nop(self):
  141. return 0
  142. def rdump(self):
  143. print 'REGISTERS::',
  144. print 'ax:', self.registers[self.REG_AX],
  145. print 'bx:', self.registers[self.REG_BX],
  146. print 'cx:', self.registers[self.REG_CX],
  147. print 'dx:', self.registers[self.REG_DX],
  148. print 'ex:', self.registers[self.REG_EX],
  149. print 'fx:', self.registers[self.REG_FX],
  150. return
  151. def mdump(self, index):
  152. print 'm[%d] ' % index, self.memory[index]
  153. return
  154. #
  155. # MEMORY MOVES
  156. #
  157. def move_i_to_r(self, src, dst):
  158. self.registers[dst] = src
  159. return 0
  160. # memory: value, register, register
  161. def move_i_to_m(self, src, value, reg1, reg2, scale):
  162. tmp = value + self.registers[reg1] + (scale * self.registers[reg2])
  163. self.memory[tmp] = src
  164. return 0
  165. def move_m_to_r(self, value, reg1, reg2, scale, dst):
  166. tmp = value + self.registers[reg1] + (scale * self.registers[reg2])
  167. self.registers[dst] = self.memory[tmp]
  168. def move_r_to_m(self, src, value, reg1, reg2, scale):
  169. tmp = value + self.registers[reg1] + (scale * self.registers[reg2])
  170. self.memory[tmp] = self.registers[src]
  171. return 0
  172. def move_r_to_r(self, src, dst):
  173. self.registers[dst] = self.registers[src]
  174. return 0
  175. #
  176. # LOAD EFFECTIVE ADDRESS (everything but the final change of memory value)
  177. #
  178. def lea_m_to_r(self, value, reg1, reg2, scale, dst):
  179. tmp = value + self.registers[reg1] + (scale * self.registers[reg2])
  180. self.registers[dst] = tmp
  181. #
  182. # ARITHMETIC INSTRUCTIONS
  183. #
  184. def add_i_to_r(self, src, dst):
  185. self.registers[dst] += src
  186. return 0
  187. def add_r_to_r(self, src, dst):
  188. self.registers[dst] += self.registers[src]
  189. return 0
  190. def mul_i_to_r(self, src, dst):
  191. self.registers[dst] *= src
  192. return 0
  193. def mul_r_to_r(self, src, dst):
  194. self.registers[dst] *= self.registers[src]
  195. return 0
  196. def sub_i_to_r(self, src, dst):
  197. self.registers[dst] -= src
  198. return 0
  199. def sub_r_to_r(self, src, dst):
  200. self.registers[dst] -= self.registers[src]
  201. return 0
  202. def neg_r(self, src):
  203. self.registers[src] = -self.registers[src]
  204. #
  205. # SUPPORT FOR LOCKS
  206. #
  207. def atomic_exchange(self, src, value, reg1, reg2):
  208. tmp = value + self.registers[reg1] + self.registers[reg2]
  209. old = self.memory[tmp]
  210. self.memory[tmp] = self.registers[src]
  211. self.registers[src] = old
  212. return 0
  213. def fetchadd(self, src, value, reg1, reg2):
  214. tmp = value + self.registers[reg1] + self.registers[reg2]
  215. old = self.memory[tmp]
  216. self.memory[tmp] = self.memory[tmp] + self.registers[src]
  217. self.registers[src] = old
  218. #
  219. # TEST for conditions
  220. #
  221. def test_all(self, src, dst):
  222. self.init_condition_codes()
  223. if dst > src:
  224. self.conditions[self.COND_GT] = True
  225. if dst >= src:
  226. self.conditions[self.COND_GTE] = True
  227. if dst < src:
  228. self.conditions[self.COND_LT] = True
  229. if dst <= src:
  230. self.conditions[self.COND_LTE] = True
  231. if dst == src:
  232. self.conditions[self.COND_EQ] = True
  233. if dst != src:
  234. self.conditions[self.COND_NEQ] = True
  235. return 0
  236. def test_i_r(self, src, dst):
  237. self.init_condition_codes()
  238. return self.test_all(src, self.registers[dst])
  239. def test_r_i(self, src, dst):
  240. self.init_condition_codes()
  241. return self.test_all(self.registers[src], dst)
  242. def test_r_r(self, src, dst):
  243. self.init_condition_codes()
  244. return self.test_all(self.registers[src], self.registers[dst])
  245. #
  246. # JUMPS
  247. #
  248. def jump(self, targ):
  249. self.PC = targ
  250. return 0
  251. def jump_notequal(self, targ):
  252. if self.conditions[self.COND_NEQ] == True:
  253. self.PC = targ
  254. return 0
  255. def jump_equal(self, targ):
  256. if self.conditions[self.COND_EQ] == True:
  257. self.PC = targ
  258. return 0
  259. def jump_lessthan(self, targ):
  260. if self.conditions[self.COND_LT] == True:
  261. self.PC = targ
  262. return 0
  263. def jump_lessthanorequal(self, targ):
  264. if self.conditions[self.COND_LTE] == True:
  265. self.PC = targ
  266. return 0
  267. def jump_greaterthan(self, targ):
  268. if self.conditions[self.COND_GT] == True:
  269. self.PC = targ
  270. return 0
  271. def jump_greaterthanorequal(self, targ):
  272. if self.conditions[self.COND_GTE] == True:
  273. self.PC = targ
  274. return 0
  275. #
  276. # CALL and RETURN
  277. #
  278. def call(self, targ):
  279. self.registers[self.REG_SP] -= 4
  280. self.memory[self.registers[self.REG_SP]] = self.PC
  281. self.PC = targ
  282. def ret(self):
  283. self.PC = self.memory[self.registers[self.REG_SP]]
  284. self.registers[self.REG_SP] += 4
  285. #
  286. # STACK and related
  287. #
  288. def push_r(self, reg):
  289. self.registers[self.REG_SP] -= 4
  290. self.memory[self.registers[self.REG_SP]] = self.registers[reg]
  291. return 0
  292. def push_m(self, value, reg1, reg2, scale):
  293. self.registers[self.REG_SP] -= 4
  294. tmp = value + self.registers[reg1] + (self.registers[reg2] * scale)
  295. # push address onto stack, not memory value itself
  296. self.memory[self.registers[self.REG_SP]] = tmp
  297. return 0
  298. def pop(self):
  299. self.registers[self.REG_SP] += 4
  300. def pop_r(self, dst):
  301. self.registers[dst] = self.memory[self.registers[self.REG_SP]]
  302. self.registers[self.REG_SP] += 4
  303. #
  304. # HELPER func for getarg
  305. #
  306. def register_translate(self, r):
  307. if r in self.regnames:
  308. return self.regnames[r]
  309. zassert(False, 'Register %s is not a valid register' % r)
  310. return
  311. def getregname(self, r):
  312. t = r.strip()
  313. if t == '':
  314. return 'zero'
  315. zassert(t[0] == '%', 'Expecting a proper register name, got [%s]' % r)
  316. return r.split('%')[1].strip()
  317. #
  318. # HELPER in parsing mov (quite primitive) and other ops
  319. # returns: (value, type)
  320. # where type is (TYPE_REGISTER, TYPE_IMMEDIATE, TYPE_MEMORY)
  321. #
  322. # FORMATS
  323. # %ax - register
  324. # $10 - immediate
  325. # 10 - direct memory
  326. # 10(%ax) - memory + reg indirect
  327. # 10(%ax,%bx) - memory + 2 reg indirect
  328. # 10(%ax,%bx,4) - XXX (not handled)
  329. #
  330. def getarg(self, arg):
  331. tmp1 = arg.replace(',', ' ')
  332. tmp = tmp1.replace(' \t', '')
  333. if tmp[0] == '$':
  334. # this is an IMMEDIATE VALUE
  335. value = tmp.split('$')[1]
  336. neg = 1
  337. if value[0] == '-':
  338. value = value[1:]
  339. neg = -1
  340. zassert(value.isdigit(), 'value [%s] must be a digit' % value)
  341. return neg * int(value), 'TYPE_IMMEDIATE'
  342. elif tmp[0] == '%':
  343. # this is a REGISTER
  344. register = tmp.split('%')[1]
  345. return self.register_translate(register), 'TYPE_REGISTER'
  346. elif tmp[0] == '.':
  347. # this is a LABEL
  348. targ = tmp
  349. return targ, 'TYPE_LABEL'
  350. elif tmp[0].isalpha() and not tmp[0].isdigit():
  351. # this is a VARIABLE
  352. zassert(tmp in self.vars, 'Variable %s is not declared' % tmp)
  353. return '%d,%d,%d,1' % (self.vars[tmp], self.register_translate('zero'), self.register_translate('zero')), 'TYPE_MEMORY'
  354. elif tmp[0].isdigit() or tmp[0] == '-' or tmp[0] == '(':
  355. # MOST GENERAL CASE: number(reg,reg) or number(reg) or number(reg,reg,number)
  356. neg = 1
  357. if tmp[0] == '-':
  358. tmp = tmp[1:]
  359. neg = -1
  360. s = tmp.split('(')
  361. if len(s) == 1:
  362. # no parens -> we just assume that we have a constant value (an address), e.g., mov 10, %ax
  363. value = neg * int(tmp)
  364. return '%d,%d,%d,1' % (int(value), self.register_translate('zero'), self.register_translate('zero')), 'TYPE_MEMORY'
  365. elif len(s) == 2:
  366. # here we just assume that we have something in parentheses
  367. # e.g., mov 10(%ax) or mov 10(%ax,%bx) or mov 10(%ax,%bx,10) or mov (%ax,%bx,10) or ...
  368. # if no leading number exists, first char should be a paren; in that case, value is just made to be 0
  369. # otherwise we should handle either a number or a negative number
  370. if tmp[0] != '(':
  371. zassert(s[0].strip().isdigit() == True, 'First number should be a digit [%s]' % s[0])
  372. value = neg * int(s[0])
  373. else:
  374. value = 0
  375. t = s[1].split(')')[0].split('__BREAK__')
  376. if len(t) == 1:
  377. register = self.getregname(t[0])
  378. return '%d,%d,%d,1' % (int(value), self.register_translate(register), self.register_translate('zero')), 'TYPE_MEMORY'
  379. elif len(t) == 2:
  380. register1 = self.getregname(t[0])
  381. register2 = self.getregname(t[1])
  382. return '%d,%d,%d,1' % (int(value), self.register_translate(register1), self.register_translate(register2)), 'TYPE_MEMORY'
  383. elif len(t) == 3:
  384. register1 = self.getregname(t[0])
  385. register2 = self.getregname(t[1])
  386. scale = int(t[2])
  387. return '%d,%d,%d,%d' % (int(value), self.register_translate(register1), self.register_translate(register2), scale), 'TYPE_MEMORY'
  388. else:
  389. print 'mov: bad argument [%s]' % tmp
  390. exit(1)
  391. return
  392. else:
  393. print 'mov: bad argument [%s]' % tmp
  394. exit(1)
  395. return
  396. zassert(True, 'mov: bad argument [%s]' % arg)
  397. return
  398. #
  399. # helper function in parsing complex args to mov/lea instruction
  400. #
  401. def removecommas(self, cline, inargs):
  402. inparen = False
  403. outargs = ''
  404. for i in range(len(inargs)):
  405. if inargs[i] == '(':
  406. zassert(inparen == False, 'cannot have nested parenthesis in argument [%s]' % cline)
  407. inparen = True
  408. if inargs[i] == ')':
  409. zassert(inparen == True, 'cannot have right parenthesis without first having left one [%s]' % cline)
  410. inparen = False
  411. if inparen == True:
  412. if inargs[i] == ',':
  413. outargs += '__BREAK__'
  414. else:
  415. outargs += inargs[i]
  416. else:
  417. outargs += inargs[i]
  418. zassert(inparen == False, 'did not close parentheses [%s]' % cline)
  419. return outargs
  420. #
  421. # LOAD a program into memory
  422. # make it ready to execute
  423. #
  424. def load(self, infile, loadaddr):
  425. pc = int(loadaddr)
  426. fd = open(infile)
  427. bpc = loadaddr
  428. data = 100
  429. for line in fd:
  430. cline = line.rstrip()
  431. # remove everything after the comment marker
  432. ctmp = cline.split('#')
  433. assert(len(ctmp) == 1 or len(ctmp) == 2)
  434. if len(ctmp) == 2:
  435. cline = ctmp[0]
  436. # remove empty lines, and split line by spaces
  437. tmp = cline.split()
  438. if len(tmp) == 0:
  439. continue
  440. # only pay attention to labels and variables
  441. if tmp[0] == '.var':
  442. assert(len(tmp) == 2 or len(tmp) == 3)
  443. assert(tmp[0] not in self.vars)
  444. self.vars[tmp[1]] = data
  445. mul = 1
  446. if len(tmp) == 3:
  447. mul = int(tmp[2])
  448. data += (4 * mul)
  449. zassert(data < bpc, 'Load address overrun by static data')
  450. if self.verbose: print 'ASSIGN VAR', tmp[0], "-->", tmp[1], self.vars[tmp[1]]
  451. elif tmp[0][0] == '.':
  452. assert(len(tmp) == 1)
  453. self.labels[tmp[0]] = int(pc)
  454. if self.verbose: print 'ASSIGN LABEL', tmp[0], "-->", pc
  455. else:
  456. pc += 1
  457. fd.close()
  458. if self.verbose: print ''
  459. # second pass: do everything else
  460. pc = int(loadaddr)
  461. fd = open(infile)
  462. for line in fd:
  463. cline = line.rstrip()
  464. # remove everything after the comment marker
  465. ctmp = cline.split('#')
  466. assert(len(ctmp) == 1 or len(ctmp) == 2)
  467. if len(ctmp) == 2:
  468. cline = ctmp[0]
  469. # remove empty lines, and split line by spaces
  470. tmp = cline.split()
  471. if len(tmp) == 0:
  472. continue
  473. # skip labels: all else must be instructions
  474. if cline[0] != '.':
  475. tmp = cline.split(None, 1)
  476. opcode = tmp[0]
  477. self.pmemory[pc] = cline.strip()
  478. if self.verbose == True:
  479. print 'opcode', opcode
  480. # MAIN OPCODE LOOP
  481. if opcode == 'mov':
  482. # most painful one to parse (due to generic form)
  483. # could be mov x(r1,r2,4), r3 or mov r1, (r2,r3) or ...
  484. outargs = self.removecommas(cline, tmp[1])
  485. rtmp = outargs.split(',')
  486. zassert(len(rtmp) == 2, 'mov: needs two args, separated by commas [%s]' % cline)
  487. arg1 = rtmp[0].strip()
  488. arg2 = rtmp[1].strip()
  489. (src, stype) = self.getarg(arg1)
  490. (dst, dtype) = self.getarg(arg2)
  491. # print 'MOV', src, stype, dst, dtype
  492. if stype == 'TYPE_MEMORY' and dtype == 'TYPE_MEMORY':
  493. print 'bad mov: two memory arguments'
  494. exit(1)
  495. elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_IMMEDIATE':
  496. print 'bad mov: two immediate arguments'
  497. exit(1)
  498. elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
  499. self.memory[pc] = 'self.move_i_to_r(%d, %d)' % (int(src), dst)
  500. elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
  501. self.memory[pc] = 'self.move_i_to_r(%d, %d)' % (int(src), dst)
  502. elif stype == 'TYPE_MEMORY' and dtype == 'TYPE_REGISTER':
  503. tmp = src.split(',')
  504. assert(len(tmp) == 4)
  505. self.memory[pc] = 'self.move_m_to_r(%d, %d, %d, %d, %d)' % (int(tmp[0]), int(tmp[1]), int(tmp[2]), int(tmp[3]), dst)
  506. elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_MEMORY':
  507. tmp = dst.split(',')
  508. assert(len(tmp) == 4)
  509. self.memory[pc] = 'self.move_r_to_m(%d, %d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2]), int(tmp[3]))
  510. elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER':
  511. self.memory[pc] = 'self.move_r_to_r(%d, %d)' % (src, dst)
  512. elif stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_MEMORY':
  513. tmp = dst.split(',')
  514. assert(len(tmp) == 4)
  515. self.memory[pc] = 'self.move_i_to_m(%d, %d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2]), int(tmp[3]))
  516. else:
  517. zassert(False, 'malformed mov instruction')
  518. elif opcode == 'lea':
  519. rtmp = tmp[1].split(',', 1)
  520. zassert(len(tmp) == 2 and len(rtmp) == 2, 'lea: needs two args, separated by commas [%s]' % cline)
  521. arg1 = rtmp[0].strip()
  522. arg2 = rtmp[1].strip()
  523. (src, stype) = self.getarg(arg1)
  524. (dst, dtype) = self.getarg(arg2)
  525. if stype == 'TYPE_MEMORY' and dtype == 'TYPE_REGISTER':
  526. tmp = src.split(',')
  527. assert(len(tmp) == 4)
  528. self.memory[pc] = 'self.lea_m_to_r(%d, %d, %d, %d, %d)' % (int(tmp[0]), int(tmp[1]), int(tmp[2]), int(tmp[3]), dst)
  529. else:
  530. zassert(False, 'malformed lea instruction (should be memory address source to register destination')
  531. elif opcode == 'neg':
  532. zassert(len(tmp) == 2, 'neg: takes one argument')
  533. arg = tmp[1].strip()
  534. (dst, dtype) = self.getarg(arg)
  535. zassert(dtype == 'TYPE_REGISTER', 'Can only neg a register')
  536. self.memory[pc] = 'self.neg_r(%d)' % dst
  537. elif opcode == 'pop':
  538. if len(tmp) == 1:
  539. self.memory[pc] = 'self.pop()'
  540. elif len(tmp) == 2:
  541. arg = tmp[1].strip()
  542. (dst, dtype) = self.getarg(arg)
  543. zassert(dtype == 'TYPE_REGISTER', 'Can only pop into a register')
  544. self.memory[pc] = 'self.pop_r(%d)' % dst
  545. else:
  546. zassert(False, 'pop instruction must take zero/one args')
  547. elif opcode == 'push':
  548. (src, stype) = self.getarg(tmp[1].strip())
  549. if stype == 'TYPE_REGISTER':
  550. self.memory[pc] = 'self.push_r(%d)' % (int(src))
  551. elif stype == 'TYPE_MEMORY':
  552. tmp = src.split(',')
  553. assert(len(tmp) == 4)
  554. self.memory[pc] = 'self.push_m(%d,%d,%d,%d)' % (int(tmp[0]), int(tmp[1]), int(tmp[2]), int(tmp[3]))
  555. else:
  556. zassert(False, 'Cannot push anything but registers')
  557. elif opcode == 'call':
  558. (targ, ttype) = self.getarg(tmp[1].strip())
  559. if ttype == 'TYPE_LABEL':
  560. self.memory[pc] = 'self.call(%d)' % (int(self.labels[targ]))
  561. else:
  562. zassert(False, 'Cannot call anything but a label')
  563. elif opcode == 'ret':
  564. assert(len(tmp) == 1)
  565. self.memory[pc] = 'self.ret()'
  566. elif opcode == 'mul':
  567. rtmp = tmp[1].split(',', 1)
  568. zassert(len(tmp) == 2 and len(rtmp) == 2, 'mul: needs two args, separated by commas [%s]' % cline)
  569. arg1 = rtmp[0].strip()
  570. arg2 = rtmp[1].strip()
  571. (src, stype) = self.getarg(arg1)
  572. (dst, dtype) = self.getarg(arg2)
  573. if stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
  574. self.memory[pc] = 'self.mul_i_to_r(%d, %d)' % (int(src), dst)
  575. elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER':
  576. self.memory[pc] = 'self.mul_r_to_r(%d, %d)' % (int(src), dst)
  577. else:
  578. zassert(False, 'malformed usage of add instruction')
  579. elif opcode == 'add':
  580. rtmp = tmp[1].split(',', 1)
  581. zassert(len(tmp) == 2 and len(rtmp) == 2, 'add: needs two args, separated by commas [%s]' % cline)
  582. arg1 = rtmp[0].strip()
  583. arg2 = rtmp[1].strip()
  584. (src, stype) = self.getarg(arg1)
  585. (dst, dtype) = self.getarg(arg2)
  586. if stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
  587. self.memory[pc] = 'self.add_i_to_r(%d, %d)' % (int(src), dst)
  588. elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER':
  589. self.memory[pc] = 'self.add_r_to_r(%d, %d)' % (int(src), dst)
  590. else:
  591. zassert(False, 'malformed usage of add instruction')
  592. elif opcode == 'sub':
  593. rtmp = tmp[1].split(',', 1)
  594. zassert(len(tmp) == 2 and len(rtmp) == 2, 'sub: needs two args, separated by commas [%s]' % cline)
  595. arg1 = rtmp[0].strip()
  596. arg2 = rtmp[1].strip()
  597. (src, stype) = self.getarg(arg1)
  598. (dst, dtype) = self.getarg(arg2)
  599. if stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
  600. self.memory[pc] = 'self.sub_i_to_r(%d, %d)' % (int(src), dst)
  601. elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER':
  602. self.memory[pc] = 'self.sub_r_to_r(%d, %d)' % (int(src), dst)
  603. else:
  604. zassert(False, 'malformed usage of sub instruction')
  605. elif opcode == 'fetchadd':
  606. rtmp = tmp[1].split(',', 1)
  607. zassert(len(tmp) == 2 and len(rtmp) == 2, 'fetchadd: needs two args, separated by commas [%s]' % cline)
  608. arg1 = rtmp[0].strip()
  609. arg2 = rtmp[1].strip()
  610. (src, stype) = self.getarg(arg1)
  611. (dst, dtype) = self.getarg(arg2)
  612. tmp = dst.split(',')
  613. assert(len(tmp) == 4)
  614. if stype == 'TYPE_REGISTER' and dtype == 'TYPE_MEMORY':
  615. self.memory[pc] = 'self.fetchadd(%d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2]))
  616. else:
  617. zassert(False, 'poorly specified fetch and add')
  618. elif opcode == 'xchg':
  619. rtmp = tmp[1].split(',', 1)
  620. zassert(len(tmp) == 2 and len(rtmp) == 2, 'xchg: needs two args, separated by commas [%s]' % cline)
  621. arg1 = rtmp[0].strip()
  622. arg2 = rtmp[1].strip()
  623. (src, stype) = self.getarg(arg1)
  624. (dst, dtype) = self.getarg(arg2)
  625. tmp = dst.split(',')
  626. assert(len(tmp) == 4)
  627. if stype == 'TYPE_REGISTER' and dtype == 'TYPE_MEMORY':
  628. self.memory[pc] = 'self.atomic_exchange(%d, %d, %d, %d)' % (src, int(tmp[0]), int(tmp[1]), int(tmp[2]))
  629. else:
  630. zassert(False, 'poorly specified atomic exchange')
  631. elif opcode == 'test':
  632. rtmp = tmp[1].split(',', 1)
  633. zassert(len(tmp) == 2 and len(rtmp) == 2, 'test: needs two args, separated by commas [%s]' % cline)
  634. arg1 = rtmp[0].strip()
  635. arg2 = rtmp[1].strip()
  636. (src, stype) = self.getarg(arg1)
  637. (dst, dtype) = self.getarg(arg2)
  638. if stype == 'TYPE_IMMEDIATE' and dtype == 'TYPE_REGISTER':
  639. self.memory[pc] = 'self.test_i_r(%d, %d)' % (int(src), dst)
  640. elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_REGISTER':
  641. self.memory[pc] = 'self.test_r_r(%d, %d)' % (int(src), dst)
  642. elif stype == 'TYPE_REGISTER' and dtype == 'TYPE_IMMEDIATE':
  643. self.memory[pc] = 'self.test_r_i(%d, %d)' % (int(src), dst)
  644. else:
  645. zassert(False, 'malformed usage of test instruction')
  646. elif opcode == 'j':
  647. (targ, ttype) = self.getarg(tmp[1].strip())
  648. zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
  649. self.memory[pc] = 'self.jump(%d)' % int(self.labels[targ])
  650. elif opcode == 'jne':
  651. (targ, ttype) = self.getarg(tmp[1].strip())
  652. zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
  653. self.memory[pc] = 'self.jump_notequal(%d)' % int(self.labels[targ])
  654. elif opcode == 'je':
  655. (targ, ttype) = self.getarg(tmp[1].strip())
  656. zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
  657. self.memory[pc] = 'self.jump_equal(%d)' % self.labels[targ]
  658. elif opcode == 'jlt':
  659. (targ, ttype) = self.getarg(tmp[1].strip())
  660. zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
  661. self.memory[pc] = 'self.jump_lessthan(%d)' % int(self.labels[targ])
  662. elif opcode == 'jlte':
  663. (targ, ttype) = self.getarg(tmp[1].strip())
  664. zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
  665. self.memory[pc] = 'self.jump_lessthanorequal(%s)' % self.labels[targ]
  666. elif opcode == 'jgt':
  667. (targ, ttype) = self.getarg(tmp[1].strip())
  668. zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
  669. self.memory[pc] = 'self.jump_greaterthan(%d)' % int(self.labels[targ])
  670. elif opcode == 'jgte':
  671. (targ, ttype) = self.getarg(tmp[1].strip())
  672. zassert(ttype == 'TYPE_LABEL', 'bad jump target [%s]' % tmp[1].strip())
  673. self.memory[pc] = 'self.jump_greaterthanorequal(%s)' % self.labels[targ]
  674. elif opcode == 'nop':
  675. self.memory[pc] = 'self.nop()'
  676. elif opcode == 'halt':
  677. self.memory[pc] = 'self.halt()'
  678. elif opcode == 'yield':
  679. self.memory[pc] = 'self.iyield()'
  680. elif opcode == 'rdump':
  681. self.memory[pc] = 'self.rdump()'
  682. elif opcode == 'mdump':
  683. self.memory[pc] = 'self.mdump(%s)' % tmp[1]
  684. else:
  685. print 'illegal opcode: ', opcode
  686. exit(1)
  687. if self.verbose: print 'pc:%d LOADING %20s --> %s' % (pc, self.pmemory[pc], self.memory[pc])
  688. # INCREMENT PC for loader
  689. pc += 1
  690. # END: loop over file
  691. fd.close()
  692. if self.verbose: print ''
  693. return
  694. # END: load
  695. def print_headers(self, procs):
  696. # print some headers
  697. if self.printstats == True:
  698. print 'icount',
  699. if len(self.memtrace) > 0:
  700. for m in self.memtrace:
  701. if m[0].isdigit():
  702. print '%5d' % int(m),
  703. else:
  704. zassert(m in self.vars, 'Traced variable %s not declared' % m)
  705. print '%5s' % m,
  706. print ' ',
  707. if len(self.regtrace) > 0:
  708. for r in self.regtrace:
  709. print '%5s' % self.get_regname(r),
  710. print ' ',
  711. if cctrace == True:
  712. print '>= > <= < != ==',
  713. # and per thread
  714. for i in range(procs.getnum()):
  715. print ' Thread %d ' % i,
  716. print ''
  717. return
  718. def print_trace(self, newline):
  719. if self.printstats == True:
  720. print '%6d' % self.icount,
  721. if len(self.memtrace) > 0:
  722. for m in self.memtrace:
  723. if self.compute:
  724. if m[0].isdigit():
  725. print '%5d' % self.memory[int(m)],
  726. else:
  727. zassert(m in self.vars, 'Traced variable %s not declared' % m)
  728. print '%5d' % self.memory[self.vars[m]],
  729. else:
  730. print '%5s' % '?',
  731. print ' ',
  732. if len(self.regtrace) > 0:
  733. for r in self.regtrace:
  734. if self.compute:
  735. print '%5d' % self.registers[r],
  736. else:
  737. print '%5s' % '?',
  738. print ' ',
  739. if cctrace == True:
  740. for c in self.condlist:
  741. if self.compute:
  742. if self.conditions[c]:
  743. print '1 ',
  744. else:
  745. print '0 ',
  746. else:
  747. print '? ',
  748. if (len(self.memtrace) > 0 or len(self.regtrace) > 0 or cctrace == True) and newline == True:
  749. print ''
  750. return
  751. def setint(self, intfreq, intrand):
  752. if intrand == False:
  753. return intfreq
  754. return int(random.random() * intfreq) + 1
  755. def run(self, procs, intfreq, intrand):
  756. # hw init: cc's, interrupt frequency, etc.
  757. if procs.ismanual() == True:
  758. intfreq = 1
  759. interrupt = 1
  760. intrand = False
  761. interrupt = self.setint(intfreq, intrand)
  762. self.icount = 0
  763. # you always get one printing
  764. print ''
  765. self.print_headers(procs)
  766. print ''
  767. self.print_trace(True)
  768. while True:
  769. if self.headercount > 0 and self.icount % self.headercount == 0 and self.icount > 0:
  770. print ''
  771. self.print_headers(procs)
  772. print ''
  773. self.print_trace(True)
  774. # need thread ID of current process
  775. tid = procs.getcurr().gettid()
  776. # FETCH
  777. prevPC = self.PC
  778. instruction = self.memory[self.PC]
  779. self.PC += 1
  780. # DECODE and EXECUTE
  781. # key: self.PC may be changed during eval; thus MUST be incremented BEFORE eval
  782. rc = eval(instruction)
  783. # tracing details: ALWAYS AFTER EXECUTION OF INSTRUCTION
  784. self.print_trace(False)
  785. # output: thread-proportional spacing followed by PC and instruction
  786. dospace(tid)
  787. print prevPC, self.pmemory[prevPC]
  788. self.icount += 1
  789. # halt instruction issued
  790. if rc == -1:
  791. procs.done()
  792. # finish execution by returning from run()
  793. if procs.numdone() == procs.getnum():
  794. return self.icount
  795. procs.next()
  796. procs.restore()
  797. self.print_trace(False)
  798. for i in range(procs.getnum()):
  799. print '----- Halt;Switch ----- ',
  800. print ''
  801. # do interrupt processing
  802. # just counts down the interrupt counter to zero
  803. # when it gets to 0, or when the 'yield' instruction is issued (rc=-2)
  804. # a switch takes place
  805. # key thing: if manual scheduling is done (procsched), interrupt
  806. # must take place every instruction for this to work
  807. interrupt -= 1
  808. if interrupt == 0 or rc == -2:
  809. interrupt = self.setint(intfreq, intrand)
  810. curr = procs.getcurr()
  811. procs.save()
  812. procs.next()
  813. procs.restore()
  814. next = procs.getcurr()
  815. if procs.ismanual() == False or (procs.ismanual() == True and curr != next):
  816. self.print_trace(False)
  817. for i in range(procs.getnum()):
  818. print '------ Interrupt ------ ',
  819. print ''
  820. # END: while
  821. return
  822. #
  823. # END: class cpu
  824. #
  825. #
  826. # PROCESS LIST class
  827. #
  828. # Tracks all running processes in the program
  829. # Also deals with manual scheduling as specified by user
  830. #
  831. class proclist:
  832. def __init__(self):
  833. self.plist = [] # list of process objects
  834. self.active = 0 # tracks how many processes are active
  835. self.manual = False
  836. self.procsched = [] # list of which processes to run in what order (by ID)
  837. self.curr = 0 # currently running process (index into procsched list)
  838. def finalize(self, procsched):
  839. if procsched == '':
  840. for i in range(len(self.plist)):
  841. self.procsched.append(i)
  842. self.curr = 0
  843. self.restore()
  844. return
  845. # in this case, user has passed in schedule
  846. self.manual = True
  847. for i in range(len(procsched)):
  848. p = int(procsched[i])
  849. if p >= self.getnum():
  850. print 'bad schedule: cannot include a thread that does not exist (%d)' % p
  851. exit(1)
  852. self.procsched.append(p)
  853. check = []
  854. for p in self.procsched:
  855. if p not in check:
  856. check.append(p)
  857. if len(check) != self.active:
  858. print 'bad schedule: does not include ALL processes', self.procsched
  859. exit(1)
  860. self.curr = 0
  861. self.restore()
  862. return
  863. def addproc(self, p):
  864. self.active += 1
  865. self.plist.append(p)
  866. return
  867. def ismanual(self):
  868. return self.manual
  869. def done(self):
  870. p = self.procsched[self.curr]
  871. self.plist[p].setdone()
  872. self.active -= 1
  873. return
  874. def numdone(self):
  875. return len(self.plist) - self.active
  876. def getnum(self):
  877. return len(self.plist)
  878. def getcurr(self):
  879. return self.plist[self.procsched[self.curr]]
  880. def save(self):
  881. self.plist[self.procsched[self.curr]].save()
  882. return
  883. def restore(self):
  884. self.plist[self.procsched[self.curr]].restore()
  885. return
  886. def next(self):
  887. while True:
  888. self.curr += 1
  889. if self.curr == len(self.procsched):
  890. self.curr = 0
  891. p = self.procsched[self.curr]
  892. if self.plist[p].isdone() == False:
  893. return
  894. return
  895. #
  896. # PROCESS class
  897. #
  898. class process:
  899. def __init__(self, cpu, tid, pc, stackbottom, reginit):
  900. self.cpu = cpu # object reference
  901. self.tid = tid
  902. self.pc = pc
  903. self.regs = {}
  904. self.cc = {}
  905. self.done = False
  906. self.stack = stackbottom
  907. # init regs: all 0 or specially set to something
  908. for r in self.cpu.get_regnums():
  909. self.regs[r] = 0
  910. if reginit != '':
  911. # form: ax=1,bx=2 (for some subset of registers)
  912. for r in reginit.split(':'):
  913. tmp = r.split('=')
  914. assert(len(tmp) == 2)
  915. self.regs[self.cpu.get_regnum(tmp[0])] = int(tmp[1])
  916. # init CCs
  917. for c in self.cpu.get_condlist():
  918. self.cc[c] = False
  919. # stack
  920. self.regs[self.cpu.get_regnum('sp')] = stackbottom
  921. return
  922. def gettid(self):
  923. return self.tid
  924. def save(self):
  925. self.pc = self.cpu.get_pc()
  926. for c in self.cpu.get_condlist():
  927. self.cc[c] = self.cpu.get_cond(c)
  928. for r in self.cpu.get_regnums():
  929. self.regs[r] = self.cpu.get_reg(r)
  930. def restore(self):
  931. self.cpu.set_pc(self.pc)
  932. for c in self.cpu.get_condlist():
  933. self.cpu.set_cond(c, self.cc[c])
  934. for r in self.cpu.get_regnums():
  935. self.cpu.set_reg(r, self.regs[r])
  936. def setdone(self):
  937. self.done = True
  938. def isdone(self):
  939. return self.done == True
  940. #
  941. # main program
  942. #
  943. parser = OptionParser()
  944. parser.add_option('-s', '--seed', default=0, help='the random seed', action='store', type='int', dest='seed')
  945. parser.add_option('-t', '--threads', default=2, help='number of threads', action='store', type='int', dest='numthreads')
  946. parser.add_option('-p', '--program', default='', help='source program (in .s)', action='store', type='string', dest='progfile')
  947. parser.add_option('-i', '--interrupt', default=50, help='interrupt frequency', action='store', type='int', dest='intfreq')
  948. parser.add_option('-P', '--procsched', default='', help='control exactly which thread runs when',
  949. action='store', type='string', dest='procsched')
  950. parser.add_option('-r', '--randints', default=False, help='if interrupts are random', action='store_true', dest='intrand')
  951. parser.add_option('-a', '--argv', default='',
  952. 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)',
  953. action='store', type='string', dest='argv')
  954. parser.add_option('-L', '--loadaddr', default=1000, help='address where to load code', action='store', type='int', dest='loadaddr')
  955. parser.add_option('-m', '--memsize', default=128, help='size of address space (KB)', action='store', type='int', dest='memsize')
  956. parser.add_option('-M', '--memtrace', default='', help='comma-separated list of addrs to trace (e.g., 20000,20001)', action='store',
  957. type='string', dest='memtrace')
  958. parser.add_option('-R', '--regtrace', default='', help='comma-separated list of regs to trace (e.g., ax,bx,cx,dx)', action='store',
  959. type='string', dest='regtrace')
  960. parser.add_option('-C', '--cctrace', default=False, help='should we trace condition codes', action='store_true', dest='cctrace')
  961. parser.add_option('-S', '--printstats',default=False, help='print some extra stats', action='store_true', dest='printstats')
  962. parser.add_option('-v', '--verbose', default=False, help='print some extra info', action='store_true', dest='verbose')
  963. parser.add_option('-H', '--headercount',default=-1, help='how often to print a row header', action='store', type='int', dest='headercount')
  964. parser.add_option('-c', '--compute', default=False, help='compute answers for me', action='store_true', dest='solve')
  965. (options, args) = parser.parse_args()
  966. print 'ARG seed', options.seed
  967. print 'ARG numthreads', options.numthreads
  968. print 'ARG program', options.progfile
  969. print 'ARG interrupt frequency', options.intfreq
  970. print 'ARG interrupt randomness',options.intrand
  971. print 'ARG procsched', options.procsched
  972. print 'ARG argv', options.argv
  973. print 'ARG load address', options.loadaddr
  974. print 'ARG memsize', options.memsize
  975. print 'ARG memtrace', options.memtrace
  976. print 'ARG regtrace', options.regtrace
  977. print 'ARG cctrace', options.cctrace
  978. print 'ARG printstats', options.printstats
  979. print 'ARG verbose', options.verbose
  980. print ''
  981. seed = int(options.seed)
  982. numthreads = int(options.numthreads)
  983. intfreq = int(options.intfreq)
  984. zassert(intfreq > 0, 'Interrupt frequency must be greater than 0')
  985. intrand = int(options.intrand)
  986. progfile = options.progfile
  987. zassert(progfile != '', 'Program file must be specified')
  988. argv = options.argv.split(',')
  989. zassert(len(argv) == numthreads or len(argv) == 1, 'argv: must be one per-thread or just one set of values for all threads')
  990. procsched = options.procsched
  991. loadaddr = options.loadaddr
  992. memsize = options.memsize
  993. memtrace = []
  994. if options.memtrace != '':
  995. for m in options.memtrace.split(','):
  996. memtrace.append(m)
  997. regtrace = []
  998. if options.regtrace != '':
  999. for r in options.regtrace.split(','):
  1000. regtrace.append(r)
  1001. cctrace = options.cctrace
  1002. printstats = options.printstats
  1003. verbose = options.verbose
  1004. hdrcount = options.headercount
  1005. #
  1006. # MAIN program
  1007. #
  1008. debug = False
  1009. debug = False
  1010. cpu = cpu(memsize, memtrace, regtrace, cctrace, options.solve, verbose, printstats, hdrcount)
  1011. # load a program
  1012. cpu.load(progfile, loadaddr)
  1013. # process list
  1014. procs = proclist()
  1015. pid = 0
  1016. stack = memsize * 1000
  1017. for t in range(numthreads):
  1018. if len(argv) > 1:
  1019. arg = argv[pid]
  1020. else:
  1021. arg = argv[0]
  1022. procs.addproc(process(cpu, pid, loadaddr, stack, arg))
  1023. stack -= 1000
  1024. pid += 1
  1025. # get first process ready to run
  1026. procs.finalize(procsched)
  1027. # run it
  1028. t1 = time.clock()
  1029. ic = cpu.run(procs, intfreq, intrand)
  1030. t2 = time.clock()
  1031. if printstats:
  1032. print ''
  1033. print 'STATS:: Instructions %d' % ic
  1034. print 'STATS:: Emulation Rate %.2f kinst/sec' % (float(ic) / float(t2 - t1) / 1000.0)
  1035. # use this for profiling
  1036. # import cProfile
  1037. # cProfile.run('run()')