/src/asm8080.pas

https://github.com/fitzer8/Z80Asm · Pascal · 1283 lines · 1007 code · 268 blank · 8 comment · 171 complexity · 8fec3d8b3935361b2002758cfd5a618f MD5 · raw file

  1. PROGRAM Asm8080;
  2. {R-}
  3. {$M 16384,0,655360}
  4. CONST
  5. maxSymLen = 16;
  6. maxOpcdLen = 4;
  7. alphaNumeric = '1234567890$ABCDEFGHIJKLMNOPQRSTUVWXYZ_';
  8. numeric = '1234567890';
  9. hex = '0123456789ABCDEF';
  10. white = #9' '; { A tab plus a space }
  11. o_Illegal = 0; { Opcode not found in FindOpcode }
  12. o_None = 1; { No operands }
  13. o_One = 2; { One byte immediate operand }
  14. o_Two = 3; { Two byte immediate operand }
  15. o_InrDcr = 4; { INR or DCR instruction }
  16. o_Arith = 5; { Register to accumulator arithmetic }
  17. o_MOV = 6; { MOV instruction }
  18. o_MVI = 7; { MVI instruction }
  19. o_LXI = 8; { LXI instruction }
  20. o_InxDcx = 9; { INX, DCX, and DAD instructions }
  21. o_PushPop = 10; { PUSH and POP instructions }
  22. o_StaxLdax = 11; { STAX and LDAX instructions }
  23. o_RST = 12; { RST instruction }
  24. o_DB = 13; { DB pseudo-op }
  25. o_DW = 14; { DW pseudo-op }
  26. o_DS = 15; { DS pseudo-op }
  27. o_EQU = -16; { EQU and SET pseudo-ops }
  28. o_ORG = -17; { ORG pseudo-op }
  29. o_END = 18; { END pseudo-op }
  30. o_LIST = -19; { LIST pseudo-op }
  31. o_OPT = -20; { OPT pseudo-op }
  32. regs = ' B C D E H L M A ';
  33. regVals = ' 0 1 2 3 4 5 6 7 ';
  34. regPairs = ' B D H SP BC DE HL ';
  35. regPairVals = ' 0 1 2 3 0 1 2 ';
  36. pushRegs = ' B D H PSW BC DE HL AF ';
  37. pushRegVals = ' 0 1 2 3 0 1 2 3 ';
  38. staxRegs = ' B D BC DE ';
  39. staxRegVals = ' 0 1 0 1 ';
  40. TYPE
  41. SymStr = String[maxSymLen];
  42. SymPtr = ^SymRec;
  43. SymRec = RECORD
  44. name: SymStr; { Symbol name }
  45. value: Integer; { Symbol value }
  46. next: SymPtr; { Pointer to next symtab entry }
  47. defined: Boolean; { TRUE if defined }
  48. multiDef: Boolean; { TRUE if multiply defined }
  49. isSet: Boolean; { TRUE if defined with SET pseudo }
  50. equ: Boolean; { TRUE if defined with EQU pseudo }
  51. END;
  52. OpcdStr = String[maxOpcdLen];
  53. OpcdPtr = ^OpcdRec;
  54. OpcdRec = RECORD
  55. name: OpcdStr; { Opcode name }
  56. typ: Integer; { Opcode type }
  57. parm: Integer; { Opcode parameter }
  58. next: OpcdPtr; { Pointer to next opcode entry }
  59. END;
  60. VAR
  61. symTab: SymPtr; { Pointer to first entry in symtab }
  62. opcdTab: OpcdPtr; { Opcode table }
  63. locPtr: Integer; { Current program address }
  64. pass: Integer; { Current assembler pass }
  65. errFlag: Boolean; { TRUE if error occurred this line }
  66. errCount: Integer; { Total number of errors }
  67. line: String; { Current line from input file }
  68. listLine: String; { Current listing line }
  69. listFlag: Boolean; { FALSE to suppress listing source }
  70. listThisLine: Boolean; { TRUE to force listing this line }
  71. sourceEnd: Boolean; { TRUE when END pseudo encountered }
  72. instr: ARRAY[1..3] OF Integer; { Current instruction word }
  73. instrLen: Integer; { Current instruction length }
  74. bytStr: String; { Buffer for long DB statements }
  75. showAddr: Boolean; { TRUE to show LocPtr on listing }
  76. xferAddr: Integer; { Transfer address from END pseudo }
  77. xferFound: Boolean; { TRUE if xfer addr defined w/ END }
  78. { Command line parameters }
  79. cl_SrcName: String; { Source file name }
  80. cl_ListName: String; { Listing file name }
  81. cl_ObjName: String; { Object file name }
  82. cl_Err: Boolean; { TRUE for errors to screen }
  83. source: Text;
  84. object: Text;
  85. listing: Text;
  86. FUNCTION Deblank(s: String): String;
  87. VAR
  88. i: Integer;
  89. BEGIN
  90. i := Length(s);
  91. WHILE (i>0) AND (s[i] IN [#9,' ']) DO
  92. Dec(i);
  93. s[0] := CHR(i);
  94. i := 1;
  95. WHILE (i<=Length(s)) AND (s[i] IN [#9,' ']) DO
  96. Inc(i);
  97. Delete(s,1,i-1);
  98. Deblank := s;
  99. END;
  100. FUNCTION UprCase(s: String): String;
  101. VAR
  102. i: Integer;
  103. BEGIN
  104. FOR i := 1 TO Length(s) DO
  105. IF s[i] IN ['a'..'z'] THEN
  106. s[i] := UpCase(s[i]);
  107. UprCase := s;
  108. END;
  109. FUNCTION Hex2(i: Integer): String;
  110. BEGIN
  111. i := i AND 255;
  112. Hex2 := Copy(hex,(i SHR 4)+1,1) + Copy(hex,(i AND 15)+1,1);
  113. END;
  114. FUNCTION Hex4(i: Integer): String;
  115. BEGIN
  116. Hex4 := Hex2(i SHR 8) + Hex2(i AND 255);
  117. END;
  118. PROCEDURE Error(message: String);
  119. BEGIN
  120. errFlag := TRUE;
  121. Inc(errCount);
  122. IF pass<>1 THEN BEGIN
  123. listThisLine := TRUE;
  124. WriteLn(listing,'*** Error: ',Message,' ***');
  125. IF cl_Err THEN WriteLn('*** Error: ',Message,' ***');
  126. END;
  127. END;
  128. PROCEDURE AddOpcode(name: OpcdStr; typ,parm: Integer);
  129. VAR
  130. p: OpcdPtr;
  131. BEGIN
  132. New(p);
  133. p^.name := name;
  134. p^.typ := typ;
  135. p^.parm := parm;
  136. p^.next := opcdTab;
  137. opcdTab := p;
  138. END;
  139. PROCEDURE FindOpcode(name: OpcdStr; VAR typ,parm: Integer);
  140. VAR
  141. p: OpcdPtr;
  142. found: Boolean;
  143. BEGIN
  144. found := FALSE;
  145. p := opcdTab;
  146. WHILE (p<>NIL) AND NOT found DO BEGIN
  147. found := (p^.name = name);
  148. IF NOT found THEN
  149. p := p^.next;
  150. END;
  151. IF NOT found THEN BEGIN
  152. typ := o_Illegal;
  153. parm := 0;
  154. END
  155. ELSE BEGIN
  156. typ := p^.typ;
  157. parm := p^.parm;
  158. END;
  159. END;
  160. PROCEDURE InitOpcodes;
  161. BEGIN
  162. opcdTab := NIL;
  163. AddOpcode('NOP' ,o_None,0);
  164. AddOpcode('RLC' ,o_None,7);
  165. AddOpcode('RRC' ,o_None,15);
  166. AddOpcode('RAL' ,o_None,23);
  167. AddOpcode('RAR' ,o_None,31);
  168. AddOpcode('DAA' ,o_None,39);
  169. AddOpcode('CMA' ,o_None,47);
  170. AddOpcode('RIM' ,o_None,48);
  171. AddOpcode('STC' ,o_None,55);
  172. AddOpcode('SIM' ,o_None,56);
  173. AddOpcode('CMC' ,o_None,63);
  174. AddOpcode('HLT' ,o_None,118);
  175. AddOpcode('RNZ' ,o_None,192);
  176. AddOpcode('RZ' ,o_None,200);
  177. AddOpcode('RET' ,o_None,201);
  178. AddOpcode('RNC' ,o_None,208);
  179. AddOpcode('RC' ,o_None,216);
  180. AddOpcode('RPO' ,o_None,224);
  181. AddOpcode('XTHL',o_None,227);
  182. AddOpcode('RPE' ,o_None,232);
  183. AddOpcode('PCHL',o_None,233);
  184. AddOpcode('XCHG',o_None,235);
  185. AddOpcode('RP' ,o_None,240);
  186. AddOpcode('DI' ,o_None,243);
  187. AddOpcode('RM' ,o_None,248);
  188. AddOpcode('SPHL',o_None,249);
  189. AddOpcode('EI' ,o_None,251);
  190. AddOpcode('ADI' ,o_One,198);
  191. AddOpcode('ACI' ,o_One,206);
  192. AddOpcode('OUT' ,o_One,211);
  193. AddOpcode('SUI' ,o_One,214);
  194. AddOpcode('IN' ,o_One,219);
  195. AddOpcode('SBI' ,o_One,222);
  196. AddOpcode('ANI' ,o_One,230);
  197. AddOpcode('XRI' ,o_One,238);
  198. AddOpcode('ORI' ,o_One,246);
  199. AddOpcode('CPI' ,o_One,254);
  200. AddOpcode('SHLD',o_Two,34);
  201. AddOpcode('LHLD',o_Two,42);
  202. AddOpcode('STA' ,o_Two,50);
  203. AddOpcode('LDA' ,o_Two,58);
  204. AddOpcode('JNZ' ,o_Two,194);
  205. AddOpcode('JMP' ,o_Two,195);
  206. AddOpcode('CNZ' ,o_Two,196);
  207. AddOpcode('JZ' ,o_Two,202);
  208. AddOpcode('CZ' ,o_Two,204);
  209. AddOpcode('CALL',o_Two,205);
  210. AddOpcode('JNC' ,o_Two,210);
  211. AddOpcode('CNC' ,o_Two,212);
  212. AddOpcode('JC' ,o_Two,218);
  213. AddOpcode('CC' ,o_Two,220);
  214. AddOpcode('JPO' ,o_Two,226);
  215. AddOpcode('CPO' ,o_Two,228);
  216. AddOpcode('JPE' ,o_Two,234);
  217. AddOpcode('CPE' ,o_Two,236);
  218. AddOpcode('JP' ,o_Two,242);
  219. AddOpcode('CP' ,o_Two,244);
  220. AddOpcode('JM' ,o_Two,250);
  221. AddOpcode('CM' ,o_Two,252);
  222. AddOpcode('INR' ,o_InrDcr,4);
  223. AddOpcode('DCR' ,o_InrDcr,5);
  224. AddOpcode('ADD' ,o_Arith,128);
  225. AddOpcode('ADC' ,o_Arith,136);
  226. AddOpcode('SUB' ,o_Arith,144);
  227. AddOpcode('SBB' ,o_Arith,152);
  228. AddOpcode('ANA' ,o_Arith,160);
  229. AddOpcode('XRA' ,o_Arith,168);
  230. AddOpcode('ORA' ,o_Arith,176);
  231. AddOpcode('CMP' ,o_Arith,184);
  232. AddOpcode('MOV' ,o_MOV,64);
  233. AddOpcode('MVI' ,o_MVI,6);
  234. AddOpcode('LXI' ,o_LXI,1);
  235. AddOpcode('INX' ,o_InxDcx,3);
  236. AddOpcode('DAD' ,o_InxDcx,9);
  237. AddOpcode('DCX' ,o_InxDcx,11);
  238. AddOpcode('POP' ,o_PushPop,193);
  239. AddOpcode('PUSH',o_PushPop,197);
  240. AddOpcode('STAX',o_StaxLdax,2);
  241. AddOpcode('LDAX',o_StaxLdax,10);
  242. AddOpcode('RST' ,o_RST,199);
  243. AddOpcode('DB' ,o_DB,0);
  244. AddOpcode('DW' ,o_DW,0);
  245. AddOpcode('DS' ,o_DS,0);
  246. AddOpcode('=' ,o_EQU,0);
  247. AddOpcode('EQU' ,o_EQU,0);
  248. AddOpcode('SET' ,o_EQU,1);
  249. AddOpcode('ORG' ,o_ORG,0);
  250. AddOpcode('END' ,o_END,0);
  251. AddOpcode('LIST',o_LIST,0);
  252. AddOpcode('OPT' ,o_OPT,0);
  253. END;
  254. FUNCTION FindSym(symName: SymStr): SymPtr;
  255. VAR
  256. p: SymPtr;
  257. found: Boolean;
  258. BEGIN
  259. found := FALSE;
  260. p := SymTab;
  261. WHILE (p<>NIL) AND NOT Found DO BEGIN
  262. found := (p^.name = symName);
  263. IF NOT found THEN
  264. p := p^.next;
  265. END;
  266. FindSym := p;
  267. END;
  268. FUNCTION AddSym(symName: SymStr): SymPtr;
  269. VAR
  270. p: SymPtr;
  271. BEGIN
  272. New(p);
  273. WITH p^ DO BEGIN
  274. name := SymName;
  275. value := 0;
  276. next := SymTab;
  277. defined := FALSE;
  278. multiDef := FALSE;
  279. isSet := FALSE;
  280. equ := FALSE;
  281. END;
  282. symTab := p;
  283. AddSym := p;
  284. END;
  285. FUNCTION RefSym(symName: SymStr): Integer;
  286. VAR
  287. p: SymPtr;
  288. BEGIN
  289. p := FindSym(symName);
  290. IF p=NIL THEN p := AddSym(symName);
  291. IF NOT p^.defined THEN
  292. Error('Symbol "' + symName + '" undefined');
  293. RefSym := p^.value;
  294. END;
  295. PROCEDURE DefSym(symName: SymStr; val: Integer; setSym,equSym: Boolean);
  296. VAR
  297. p: SymPtr;
  298. BEGIN
  299. IF Length(symName)<>0 THEN BEGIN
  300. p := FindSym(symName);
  301. IF p=NIL THEN p := AddSym(symName);
  302. IF (NOT p^.defined) OR (p^.isSet AND setSym) THEN BEGIN
  303. p^.value := val;
  304. p^.defined := TRUE;
  305. p^.isSet := setSym;
  306. p^.equ := equSym;
  307. END
  308. ELSE IF p^.value <> val THEN BEGIN
  309. p^.multiDef := TRUE;
  310. Error('Symbol "' + symName + '" multiply defined');
  311. END;
  312. END;
  313. END;
  314. FUNCTION GetWord: String;
  315. VAR
  316. word: String;
  317. done: Boolean;
  318. BEGIN
  319. line := Deblank(line);
  320. word := '';
  321. IF Length(line)>0 THEN
  322. IF (line[1]=#12) OR (line[1]=';') THEN
  323. line := '';
  324. IF Length(line)>0 THEN BEGIN
  325. IF Pos(Upcase(line[1]),alphaNumeric)=0 THEN BEGIN
  326. word := Copy(Line,1,1);
  327. Delete(line,1,1);
  328. END
  329. ELSE BEGIN
  330. done := FALSE;
  331. WHILE (Length(line)>0) AND NOT done DO BEGIN
  332. word := word + Upcase(line[1]);
  333. Delete(line,1,1);
  334. IF Length(line)>0 THEN
  335. done := Pos(Upcase(line[1]),AlphaNumeric)=0;
  336. END;
  337. END;
  338. END;
  339. GetWord := word;
  340. END;
  341. PROCEDURE Expect(expected: String);
  342. BEGIN
  343. IF GetWord<>expected THEN
  344. Error('"' + expected + '" expected');
  345. END;
  346. PROCEDURE Comma;
  347. BEGIN
  348. Expect(',');
  349. END;
  350. FUNCTION EvalOct(octStr: String): Integer;
  351. VAR
  352. octVal: Integer;
  353. evalErr: Boolean;
  354. i,n: Integer;
  355. BEGIN
  356. evalErr := FALSE;
  357. octVal := 0;
  358. FOR i := 1 TO Length(octStr) DO BEGIN
  359. n := Pos(octStr[i],'01234567');
  360. IF n=0 THEN evalErr := TRUE
  361. ELSE octVal := octVal*8 + n-1;
  362. END;
  363. IF evalErr THEN BEGIN
  364. octVal := 0;
  365. Error('Invalid octal number');
  366. END;
  367. EvalOct := octVal;
  368. END;
  369. FUNCTION EvalDec(decStr: String): Integer;
  370. VAR
  371. decVal: Integer;
  372. evalErr: Boolean;
  373. i,n: Integer;
  374. BEGIN
  375. evalErr := FALSE;
  376. decVal := 0;
  377. FOR i := 1 TO Length(decStr) DO BEGIN
  378. n := Pos(decStr[i],'0123456789');
  379. IF n=0 THEN evalErr := TRUE
  380. ELSE decVal := decVal*10 + n-1;
  381. END;
  382. IF evalErr THEN BEGIN
  383. decVal := 0;
  384. Error('Invalid decimal number');
  385. END;
  386. EvalDec := decVal;
  387. END;
  388. FUNCTION EvalHex(hexStr: String): Integer;
  389. VAR
  390. hexVal: Integer;
  391. evalErr: Boolean;
  392. i,n: Integer;
  393. BEGIN
  394. evalErr := FALSE;
  395. hexVal := 0;
  396. FOR i := 1 TO Length(hexStr) DO BEGIN
  397. n := Pos(Upcase(hexStr[i]),'0123456789ABCDEF');
  398. IF n=0 THEN evalErr := TRUE
  399. ELSE hexVal := hexVal*16 + n-1;
  400. END;
  401. IF evalErr THEN BEGIN
  402. hexVal := 0;
  403. Error('Invalid hexadecimal number');
  404. END;
  405. EvalHex := hexVal;
  406. END;
  407. FUNCTION Eval: Integer; FORWARD;
  408. FUNCTION Factor: Integer;
  409. VAR
  410. word: String;
  411. val: Integer;
  412. BEGIN
  413. word := GetWord;
  414. val := 0;
  415. IF Length(word)=0 THEN Error('Missing operand')
  416. ELSE IF (word='.') OR (word='*') THEN val := locPtr
  417. ELSE IF word='-' THEN val := -Factor
  418. ELSE IF word='+' THEN val := Factor
  419. ELSE IF word='~' THEN val := -Factor-1
  420. ELSE IF word='(' THEN BEGIN
  421. val := Eval;
  422. Expect(')');
  423. END
  424. ELSE IF word='''' THEN BEGIN
  425. IF Length(line)=0 THEN
  426. Error('Missing operand')
  427. ELSE BEGIN
  428. val := Ord(line[1]);
  429. Delete(line,1,1);
  430. Expect('''');
  431. END;
  432. END
  433. ELSE IF Pos(word[1],numeric)>0 THEN BEGIN
  434. CASE word[Length(word)] OF
  435. 'O': val := EvalOct(Copy(word,1,Length(word)-1));
  436. 'D': val := EvalDec(Copy(word,1,Length(word)-1));
  437. 'H': val := EvalHex(Copy(word,1,Length(word)-1));
  438. ELSE val := EvalDec(word);
  439. END;
  440. END
  441. ELSE val := RefSym(word);
  442. Factor := val;
  443. END;
  444. FUNCTION Term: Integer;
  445. VAR
  446. word: String;
  447. val: Integer;
  448. oldLine: String;
  449. BEGIN
  450. val := Factor;
  451. oldLine := line;
  452. word := GetWord;
  453. WHILE (word='*') OR (word='/') OR (word='%') DO BEGIN
  454. CASE word[1] OF
  455. '*': val := val * Factor;
  456. '/': val := val DIV Factor;
  457. '%': val := val MOD Factor;
  458. END;
  459. oldLine := line;
  460. word := GetWord;
  461. END;
  462. line := oldLine;
  463. Term := val;
  464. END;
  465. FUNCTION Eval: Integer;
  466. VAR
  467. word: String;
  468. val: Integer;
  469. oldLine: String;
  470. BEGIN
  471. val := Term;
  472. oldLine := line;
  473. word := GetWord;
  474. WHILE (word='+') OR (word='-') {OR (word='*') OR (word='/')} DO BEGIN
  475. CASE word[1] OF
  476. '+': val := val + Term;
  477. '-': val := val - Term;
  478. END;
  479. oldLine := line;
  480. word := GetWord;
  481. END;
  482. line := oldLine;
  483. Eval := val;
  484. END;
  485. FUNCTION EvalByte: Integer;
  486. VAR
  487. val: Integer;
  488. BEGIN
  489. val := Eval;
  490. IF (val<-128) OR (val>255) THEN
  491. Error('Byte out of range');
  492. EvalByte := val AND 255;
  493. END;
  494. FUNCTION FindReg(regName,regList,valList: String): Integer;
  495. VAR
  496. p: Integer;
  497. reg: Integer;
  498. code: Integer;
  499. BEGIN
  500. p := Pos(' ' + Deblank(regName) + ' ',regList);
  501. IF p=0 THEN BEGIN
  502. reg := 0;
  503. Error('Illegal register "' + Deblank(RegName) + '"');
  504. END
  505. ELSE
  506. Val(Copy(valList,p,2),reg,code);
  507. FindReg := reg;
  508. END;
  509. PROCEDURE CodeOut(byte: Integer);
  510. BEGIN
  511. IF pass=2 THEN
  512. WriteLn(object,Hex2(byte));
  513. END;
  514. PROCEDURE CodeOrg(addr: Integer);
  515. BEGIN
  516. locPtr := addr;
  517. IF pass=2 THEN
  518. WriteLn(object,':',Hex4(addr));
  519. END;
  520. PROCEDURE CodeFlush;
  521. BEGIN
  522. { Object file format does not use buffering; no flush needed }
  523. END;
  524. PROCEDURE CodeEnd;
  525. BEGIN
  526. CodeFlush;
  527. IF (pass=2) AND xferFound THEN BEGIN
  528. WriteLn(object,'$',Hex4(xferAddr));
  529. END;
  530. END;
  531. PROCEDURE CodeXfer(addr: Integer);
  532. BEGIN
  533. xferAddr := addr;
  534. xferFound := TRUE;
  535. END;
  536. PROCEDURE DoOpcode(typ,parm: Integer);
  537. VAR
  538. val: Integer;
  539. reg1: Integer;
  540. reg2: Integer;
  541. word: String;
  542. oldLine: String;
  543. BEGIN
  544. CASE typ OF
  545. o_None: BEGIN
  546. instr[1] := parm;
  547. instrLen := 1;
  548. END;
  549. o_One: BEGIN
  550. instr[1] := parm;
  551. instr[2] := EvalByte;
  552. instrLen := 2;
  553. END;
  554. o_Two: BEGIN
  555. val := Eval;
  556. instr[1] := parm;
  557. instr[2] := val AND 255;
  558. instr[3] := val SHR 8;
  559. instrLen := 3;
  560. END;
  561. o_InrDcr: BEGIN
  562. reg1 := FindReg(GetWord,regs,regVals);
  563. instr[1] := parm + reg1*8;
  564. instrLen := 1;
  565. END;
  566. o_Arith: BEGIN
  567. reg1 := FindReg(GetWord,regs,regVals);
  568. instr[1] := parm + reg1;
  569. instrLen := 1;
  570. END;
  571. o_MOV: BEGIN
  572. reg1 := FindReg(GetWord,regs,regVals);
  573. Comma;
  574. reg2 := FindReg(GetWord,regs,regVals);
  575. instr[1] := parm + reg1*8 + reg2;
  576. instrLen := 1;
  577. END;
  578. o_MVI: BEGIN
  579. reg1 := FindReg(GetWord,regs,regVals);
  580. Comma;
  581. instr[1] := parm + reg1*8;
  582. instr[2] := EvalByte;
  583. instrLen := 2;
  584. END;
  585. o_LXI: BEGIN
  586. reg1 := FindReg(GetWord,regPairs,regPairVals);
  587. Comma;
  588. val := Eval;
  589. instr[1] := parm + reg1*16;
  590. instr[2] := val AND 255;
  591. instr[3] := val SHR 8;
  592. instrLen := 3;
  593. END;
  594. o_InxDcx: BEGIN
  595. reg1 := FindReg(GetWord,regPairs,regPairVals);
  596. instr[1] := parm + reg1*16;
  597. instrLen := 1;
  598. END;
  599. o_PushPop: BEGIN
  600. reg1 := FindReg(GetWord,pushRegs,pushRegVals);
  601. instr[1] := parm + reg1*16;
  602. instrLen := 1;
  603. END;
  604. o_StaxLdax: BEGIN
  605. reg1 := FindReg(GetWord,staxRegs,staxRegVals);
  606. instr[1] := parm + reg1*16;
  607. instrLen := 1;
  608. END;
  609. o_RST: BEGIN
  610. val := Eval;
  611. CASE val OF
  612. 0,1,2,3,4,5,6,7: val := val * 8;
  613. 8,16,24,32,40,48,56: ;
  614. ELSE BEGIN
  615. Error('Illegal restart number');
  616. val := 0;
  617. END;
  618. END;
  619. instr[1] := parm + val;
  620. instrLen := 1;
  621. END;
  622. o_DB: BEGIN
  623. oldLine := line;
  624. word := GetWord;
  625. IF word='''' THEN BEGIN
  626. val := Pos('''',line);
  627. IF val=0 THEN BEGIN
  628. bytStr := line;
  629. line := '';
  630. END
  631. ELSE BEGIN
  632. bytStr := Copy(line,1,val-1);
  633. Delete(line,1,val);
  634. END;
  635. instrLen := -Length(bytStr);
  636. END
  637. ELSE BEGIN
  638. line := oldLine;
  639. instr[1] := EvalByte;
  640. instrLen := 1;
  641. END;
  642. END;
  643. o_DW: BEGIN
  644. val := Eval;
  645. instr[1] := val AND 255;
  646. instr[2] := val SHR 8;
  647. instrLen := 2;
  648. END;
  649. o_DS: BEGIN
  650. val := Eval;
  651. IF pass=2 THEN BEGIN
  652. showAddr := FALSE;
  653. Delete(listLine,1,13);
  654. listLine := Hex4(locPtr) + ': (' + Hex4(val) + ')'
  655. + listLine;
  656. END;
  657. val := val + locPtr;
  658. CodeOrg(val);
  659. END;
  660. o_END: BEGIN
  661. oldLine := line;
  662. IF Length(GetWord)<>0 THEN BEGIN
  663. line := oldLine;
  664. val := Eval;
  665. CodeXfer(val);
  666. line := Copy(line,1,7) + '(' + Hex4(val) + ')' +
  667. Copy(line,14,255);
  668. END;
  669. sourceEnd := TRUE;
  670. END;
  671. ELSE Error('Unknown opcode');
  672. END;
  673. END;
  674. PROCEDURE DoLabelOp(typ,parm: Integer; labl: SymStr);
  675. VAR
  676. val: Integer;
  677. word: String;
  678. BEGIN
  679. CASE typ OF
  680. o_EQU: BEGIN
  681. IF Length(labl)=0 THEN
  682. Error('Missing label')
  683. ELSE BEGIN
  684. val := Eval;
  685. listLine := Copy(listLine,1,6) + '= ' + Hex4(val) +
  686. Copy(listLine,13,255);
  687. DefSym(labl,val,parm=1,parm=0);
  688. END;
  689. END;
  690. o_ORG: BEGIN
  691. CodeOrg(Eval);
  692. DefSym(labl,locPtr,FALSE,FALSE);
  693. showAddr := TRUE;
  694. END;
  695. o_LIST: BEGIN
  696. listThisLine := TRUE;
  697. IF Length(labl)<>0 THEN
  698. Error('Label not allowed');
  699. word := GetWord;
  700. IF word='ON' THEN listFlag := TRUE
  701. ELSE IF word='OFF' THEN listFlag := FALSE
  702. ELSE Error('Illegal operand');
  703. END;
  704. o_OPT: BEGIN
  705. listThisLine := TRUE;
  706. IF Length(labl)<>0 THEN
  707. Error('Label not allowed');
  708. word := GetWord;
  709. IF word='LIST' THEN listFlag := TRUE
  710. ELSE IF word='NOLIST' THEN listFlag := FALSE
  711. ELSE Error('Illegal option');
  712. END;
  713. ELSE Error('Unknown opcode');
  714. END;
  715. END;
  716. PROCEDURE ListOut;
  717. VAR
  718. i: Integer;
  719. BEGIN
  720. IF Deblank(listLine) = #12 THEN
  721. WriteLn(listing,#12)
  722. ELSE IF Deblank(listLine)='' THEN
  723. WriteLn(listing)
  724. ELSE BEGIN
  725. i := Length(listLine);
  726. WHILE (i>0) AND (listLine[i]=' ') DO
  727. Dec(i);
  728. listLine[0] := CHR(i);
  729. WriteLn(listing,listLine);
  730. IF errFlag AND cl_Err THEN
  731. WriteLn(listLine);
  732. END;
  733. END;
  734. PROCEDURE DoPass;
  735. VAR
  736. labl: SymStr;
  737. opcode: OpcdStr;
  738. typ: Integer;
  739. parm: Integer;
  740. i: Integer;
  741. word: String;
  742. BEGIN
  743. Assign(source,cl_SrcName);
  744. Reset(source);
  745. sourceEnd := FALSE;
  746. WriteLn('Pass ',pass);
  747. CodeOrg(0);
  748. errCount := 0;
  749. listFlag := TRUE;
  750. WHILE (NOT Eof(source)) AND (NOT SourceEnd) DO BEGIN
  751. ReadLn(source,line);
  752. errFlag := FALSE;
  753. instrLen := 0;
  754. showAddr := FALSE;
  755. listThisLine := ListFlag;
  756. listLine := ' '; { 16 blanks }
  757. IF Pass=2 THEN listLine := Copy(listLine,1,16) + line;
  758. labl := '';
  759. IF Length(line)>0 THEN
  760. IF Pos(line[1],white)=0 THEN BEGIN
  761. labl := GetWord;
  762. showAddr := (Length(labl)<>0);
  763. IF Length(line)>0 THEN
  764. IF line[1]=':' THEN
  765. Delete(line,1,1);
  766. END;
  767. opcode := GetWord;
  768. IF Length(opcode)=0 THEN BEGIN
  769. typ := 0;
  770. DefSym(labl,locPtr,FALSE,FALSE);
  771. END
  772. ELSE BEGIN
  773. FindOpcode(opcode,typ,parm);
  774. IF typ=o_Illegal THEN Error('Illegal opcode "' +
  775. Deblank(opcode) + '"')
  776. ELSE IF typ<0 THEN BEGIN
  777. showAddr := FALSE;
  778. DoLabelOp(typ,parm,labl);
  779. END
  780. ELSE BEGIN
  781. showAddr := TRUE;
  782. DefSym(labl,locPtr,FALSE,FALSE);
  783. DoOpcode(typ,parm);
  784. END;
  785. IF typ<>o_Illegal THEN
  786. IF Length(GetWord)>0 THEN
  787. Error('Too many operands');
  788. END;
  789. IF Pass=2 THEN BEGIN
  790. IF ShowAddr THEN
  791. listLine := Hex4(locPtr) + ':' + Copy(listLine,6,255);
  792. IF instrLen>0 THEN
  793. FOR i := 1 TO instrLen DO BEGIN
  794. word := Hex2(instr[i]);
  795. listLine[i*3+4] := word[1];
  796. listLine[i*3+5] := word[2];
  797. CodeOut(instr[I]);
  798. END
  799. ELSE FOR i := 1 TO -instrLen DO BEGIN
  800. IF I<=3 THEN BEGIN
  801. word := Hex2(ORD(bytStr[i]));
  802. listLine[i*3+4] := word[1];
  803. listLine[i*3+5] := word[2];
  804. END;
  805. CodeOut(ORD(bytStr[i]));
  806. END;
  807. IF listThisLine THEN ListOut;
  808. END;
  809. locPtr := locPtr + ABS(instrLen);
  810. END;
  811. IF Pass=2 THEN CodeEnd;
  812. { Put the lines after the END statement into the listing file }
  813. { while still checking for listing control statements. Ignore }
  814. { any lines which have invalid syntax, etc., because whatever }
  815. { is found after an END statement should esentially be ignored. }
  816. IF Pass=2 THEN
  817. WHILE NOT Eof(source) DO BEGIN
  818. listThisLine := listFlag;
  819. listLine := ' ' + line; { 16 blanks }
  820. IF Length(line)>0 THEN
  821. IF Pos(line[1],white)<>0 THEN BEGIN
  822. word := GetWord;
  823. IF Length(word)<>0 THEN BEGIN
  824. IF word='LIST' THEN
  825. BEGIN
  826. listThisLine := TRUE;
  827. word := GetWord;
  828. IF word='ON' THEN listFlag := TRUE
  829. ELSE IF word='OFF' THEN listFlag := FALSE
  830. ELSE listThisLine := listFlag;
  831. END
  832. ELSE IF word='OPT' THEN
  833. BEGIN
  834. listThisLine := TRUE;
  835. word := GetWord;
  836. IF word='LIST' THEN listFlag := TRUE
  837. ELSE IF word='NOLIST' THEN listFlag := FALSE
  838. ELSE listThisLine := listFlag;
  839. END;
  840. END;
  841. END;
  842. IF listThisLine THEN ListOut;
  843. END;
  844. Close(source);
  845. END;
  846. PROCEDURE SortSymTab;
  847. VAR
  848. i,j,t: SymPtr;
  849. sorted: Boolean;
  850. temp: SymRec;
  851. BEGIN
  852. IF symTab<>NIL THEN BEGIN
  853. i := symTab;
  854. j := i^.next;
  855. WHILE (j<>NIL) DO BEGIN
  856. sorted := TRUE;
  857. WHILE (j<>NIL) DO BEGIN
  858. IF j^.name < i^.name THEN BEGIN
  859. temp := i^;
  860. i^ := j^;
  861. j^ := temp;
  862. t := i^.next;
  863. i^.next := j^.next;
  864. j^.next := t;
  865. sorted := FALSE;
  866. END;
  867. j := j^.next;
  868. END;
  869. i := i^.next;
  870. j := i^.next;
  871. END;
  872. END;
  873. END;
  874. PROCEDURE DumpSym(p: SymPtr);
  875. BEGIN
  876. Write(listing,p^.name:maxSymLen,' ',Hex4(p^.value));
  877. IF NOT p^.defined THEN Write(listing,' U');
  878. IF p^.multiDef THEN Write(listing,' M');
  879. IF p^.isSet THEN Write(listing,' S');
  880. IF p^.equ THEN Write(listing,' E');
  881. WriteLn(listing);
  882. END;
  883. PROCEDURE DumpSymTab;
  884. VAR
  885. p: SymPtr;
  886. BEGIN
  887. SortSymTab;
  888. p := symTab;
  889. WHILE (p<>NIL) DO BEGIN
  890. DumpSym(p);
  891. p := p^.next;
  892. END;
  893. END;
  894. PROCEDURE ShowOptions;
  895. BEGIN
  896. WriteLn;
  897. WriteLn(' Command line syntax:');
  898. WriteLn;
  899. WriteLn(' ASM8080 [options] src [options]');
  900. WriteLn;
  901. WriteLn(' Valid options:');
  902. WriteLn;
  903. WriteLn(' -E Show errors to screen');
  904. WriteLn(' -L Make a listing file to src.LIS');
  905. WriteLn(' -L=name');
  906. WriteLn(' -O Make an object file to src.OBJ');
  907. WriteLn(' -O=name');
  908. WriteLn;
  909. END;
  910. FUNCTION GetOption(VAR optStr: String): String;
  911. VAR
  912. option: String[80];
  913. p: Integer;
  914. BEGIN
  915. optStr := Deblank(optStr);
  916. p := Pos(' ',optStr);
  917. IF p=0 THEN BEGIN
  918. option := optStr;
  919. optStr := '';
  920. END
  921. ELSE BEGIN
  922. option := Copy(optStr,1,p-1);
  923. optStr := Copy(optStr,p+1,255);
  924. END;
  925. optStr := UprCase(Deblank(optStr));
  926. GetOption := option;
  927. END;
  928. FUNCTION GetOptions(VAR cl_SrcName, cl_ListName,cl_ObjName: String; VAR cl_Err: Boolean): Boolean;
  929. VAR
  930. s: String;
  931. len: Integer;
  932. optStr: String;
  933. option: String;
  934. optParm: String;
  935. prefix: String;
  936. p: Integer;
  937. err: Integer;
  938. optErr: Boolean;
  939. i: Integer;
  940. BEGIN
  941. cl_SrcName := '';
  942. cl_ListName := 'NUL';
  943. cl_ObjName := 'NUL';
  944. cl_Err := FALSE;
  945. optErr := FALSE;
  946. optStr := ParamStr(1);
  947. FOR i := 2 TO ParamCount DO
  948. optStr := optStr + ' ' + ParamStr(i);
  949. option := GetOption(optStr);
  950. WHILE Length(option)<>0 DO BEGIN
  951. optParm := '';
  952. p := Pos('=',option);
  953. IF p>0 THEN BEGIN
  954. optParm := Copy(option,p+1,255);
  955. option := Copy(option,1,p-1);
  956. END;
  957. IF option = '-L' THEN cl_ListName := optParm
  958. ELSE IF option = '-O' THEN cl_ObjName := optParm
  959. ELSE IF option = '-E' THEN cl_Err := TRUE
  960. ELSE IF option = '?' THEN optErr := TRUE
  961. ELSE BEGIN
  962. IF (Copy(option,1,1)='-') OR (Length(cl_SrcName)<>0) OR
  963. (Length(optParm)<>0) THEN BEGIN
  964. optErr := TRUE;
  965. WriteLn('Illegal command line option: ',option);
  966. END
  967. ELSE BEGIN
  968. cl_SrcName := option;
  969. IF Pos('.',cl_SrcName)=0 THEN
  970. IF p=0 THEN cl_SrcName := cl_SrcName + '.ASM';
  971. p := Pos('.',option);
  972. IF p=0 THEN prefix := option
  973. ELSE prefix := Copy(option,1,p-1);
  974. END;
  975. END;
  976. option := GetOption(optStr);
  977. END;
  978. IF cl_SrcName = '' THEN BEGIN
  979. optErr := TRUE;
  980. WriteLn('Source file not specified')
  981. END;
  982. IF cl_ListName = '' THEN cl_ListName := prefix + '.LIS';
  983. IF cl_ObjName = '' THEN cl_ObjName := prefix + '.DAT';
  984. IF Copy(cl_ListName,1,1)='.' THEN cl_ListName := prefix + cl_ListName;
  985. IF Copy(cl_ObjName ,1,1)='.' THEN cl_ObjName := prefix + cl_ObjName;
  986. GetOptions := optErr;
  987. END;
  988. BEGIN
  989. IF GetOptions(cl_SrcName,cl_ListName,cl_ObjName,cl_Err) THEN BEGIN
  990. ShowOptions;
  991. Halt;
  992. END;
  993. Assign(listing,cl_ListName);
  994. Rewrite(listing);
  995. Assign(object,cl_ObjName);
  996. Rewrite(object);
  997. symTab := NIL;
  998. xferAddr := 0;
  999. xferFound := FALSE;
  1000. InitOpcodes;
  1001. pass := 1;
  1002. DoPass;
  1003. pass := 2;
  1004. DoPass;
  1005. WriteLn(listing);
  1006. WriteLn(listing,errCount:5,' Total Error(s)');
  1007. WriteLn(listing);
  1008. IF cl_Err THEN BEGIN
  1009. WriteLn;
  1010. WriteLn(errCount:5,' Total Error(s)');
  1011. END;
  1012. DumpSymTab;
  1013. Close(listing);
  1014. Close(object);
  1015. END.