├── LICENSE ├── README.md ├── tenth.s ├── as6.c └── as.c /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 aap 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tenth 2 | A simple bare-metal forth for PDP-10 3 | 4 | ## Why? 5 | Ever since I got to play with [Jörg Hoppe's awesome KI10 front panel](http://retrocmp.com/stories/the-pdp-10-ki10-console-panel) 6 | at the [VCFB 2014](http://vcfb.de/2014/) I wanted to do something with the PDP-10. 7 | To have something to show at the [VCFB 2015](http://vcfb.de/2015/) I wrote a simple assembler 8 | and started to write some basic console IO functions. 9 | I began to really like the instruction set and started porting my very primitive [PDP-11 forth](https://github.com/aap/ainliforth). 10 | Since this time I used an assembler it was much faster to modify the code and I got the basics working in time for the VCFB. 11 | The next few days after the VCFB I extended it a bit to make it presentable. 12 | I used jonesforth as a guide or inspiration for some things but the main code was written independently. 13 | 14 | ## Notes on the assembler 15 | This is a very simple assembler. Its syntax is neither that of MACRO10 nor that of MIDAS. It reads from stdin and outputs `a.rim`, 16 | which can be loaded by simh with `load a.rim`. 17 | 18 | ## Notes on forth 19 | This forth is case sensitive, use upper case. 20 | 21 | The PDP-10 is word and not byte addressed so I had to think of a way to store strings. 22 | Storing an ASCII character (7 bits) into 36 bits seemed wasteful so I used the PDP-10's byte instructions to pack 5 characters into one word. 23 | This makes handling strings a bit awkwards and currently all code handling them is implemented in assembly. 24 | I've not decided how to expose this in forth yet. 25 | 26 | Only a subset of forth words are implemented as of now. Since the only input method is via terminal all definitions 27 | must be compiled by hand. The plan is to write a paper tape driver and to load forth code from there. 28 | 29 | Defined words: 30 | EXIT INTERPRET QUIT ABORT CREATE : ; CONSTANT VARIABLE BRANCH 0BRANCH (LITERAL) , [ ] . .S 31 | DROP SWAP DUP ?DUP OVER ROT -ROT >R R> R@ RSP@ 1+ 1- + - * /MOD / MOD = <> < <= > >= 0= 0<> 0< 0<= 0> 0>= AND OR XOR NOT 32 | ABS NEGATE MIN MAX WORD ! +! @ HERE STATE BASE >IN IF THEN ELSE BEGIN AGAIN WHILE REPEAT DO UNLOOP LOOP +LOOP I J EMIT KEY CR 33 | SPACE 34 | 35 | There is no real error handling. When a word isn't found in the dictionary it panics and goes into an endless loop. 36 | 37 | I did not implement any standard although I used FORTH-79 for reference often. 38 | 39 | Lastly I hope my assembly is at least somewhat idiomatic. I've been programming PDP-10 assembly for only 1-2 weeks now 40 | so my experience is limited and I have not read much other PDP-10 code yet. I'd like to hear your criticism. 41 | 42 | ## How to run in simh 43 | Compile `as.c` and assemble `tenth.s` with `./as < tenth.s`. 44 | Start `pdp10` from simh and `load a.rim` to load the paper tape into memory. 45 | Start execution with `go` 46 | -------------------------------------------------------------------------------- /tenth.s: -------------------------------------------------------------------------------- 1 | X=14 # pointer into code/parameter field 2 | PC=15 # the interpreter's program counter 3 | PP=16 # parameter stack pointer 4 | P=17 # return stack pointer 5 | APR=0 6 | CTYIN=32 7 | CTYOUT=33 8 | 9 | PDLLEN=100 10 | PDL: .=.+PDLLEN 11 | PPDL: .=.+PDLLEN 12 | RSP: -PDLLEN,,PDL-1 13 | PSP: -PDLLEN,,PPDL-1 14 | INP: 0 15 | INBUF: 0; .=.+40 16 | INBUFBP: 440700,,INBUF+1 17 | WORDBUF: 0; .=.+10 18 | WORDBUFBP: 440700,,WORDBUF+1 19 | 20 | START: 21 | SETZM CTYIN 22 | MOVE P,RSP 23 | MOVE PP,PSP 24 | MOVEI PC,{ _QUIT } 25 | JRST NEXT 26 | 27 | # 28 | # output 29 | # 30 | 31 | # print ASCII character in AC 0 - changes AC 0 32 | PUTCHAR: 33 | IORI 0,400 # valid bit 34 | MOVEM 0,CTYOUT 35 | CONO APR,12000 # 10000 = set flags, 2000 = interrupt flag 36 | SKIPE CTYOUT # wait for transmission to complete 37 | JRST .-1 38 | CAIE 0,400|"\n 39 | POPJ P, 40 | MOVEI 0,"\r 41 | JRST PUTCHAR 42 | 43 | # print null-terminated ASCII string in AC 0 - changes AC 0 1 44 | PUTS: 45 | MOVE 1,0 # address 46 | HRLI 1,440700 # 7-bit bytes 47 | ILDB 0,1 48 | CAIN 0,0 49 | POPJ P, 50 | PUSHJ P,PUTCHAR 51 | JRST .-4 52 | 53 | # prints a counted ASCII string in AC 0 54 | PUTSN: 55 | MOVE 2,@0 # char count 56 | AOS 0 57 | MOVE 1,0 58 | HRLI 1,440700 59 | PUTSN1: SOSGE 2 60 | POPJ P, 61 | ILDB 0,1 62 | PUSHJ P,PUTCHAR 63 | JRST PUTSN1 64 | 65 | # print 'panic' and halt 66 | PANIC: 67 | MOVEI 0,{ ASCII "\npanic\n\0" } 68 | PUSHJ P,PUTS 69 | JRST 4,. 70 | 71 | BASE: 12 72 | DIGITS: "0; "1; "2; "3; "4; "5; "6; "7; "8; "9; "A; "B; "C; "D; "E; "F 73 | 74 | # print number in AC 1 - changes AC 0 1 2 75 | PRINTN: 76 | JUMPGE 1,UPRINTN 77 | MOVEI 0,"- 78 | PUSHJ P,PUTCHAR 79 | MOVM 1,1 80 | UPRINTN: 81 | IDIV 1,BASE 82 | JUMPE 1,UPR1 83 | PUSH P,2 84 | PUSHJ P,UPRINTN 85 | POP P,2 86 | UPR1: 87 | MOVE 0,DIGITS(2) 88 | JRST PUTCHAR 89 | 90 | # prints number in AC 1 and a space - changes AC 0 1 91 | PRINTNSP: 92 | PUSHJ P,PRINTN 93 | MOVEI 0,40 # space 94 | JRST PUTCHAR 95 | 96 | # reads one character into AC 0 97 | GETCH: 98 | CONO APR,12000 # 10000 = set flags, 2000 = interrupt flag 99 | MOVE 0,CTYIN 100 | CAIN 0,0 101 | JRST .-2 102 | SETZM CTYIN 103 | TRZ 0,400 104 | CAIN 0,"\r 105 | MOVEI 0,"\n 106 | POPJ P, 107 | 108 | # 109 | # input 110 | # 111 | 112 | # reads one character into AC 0 and echos - changes AC 0 1 113 | GETCHAR: 114 | PUSHJ P,GETCH 115 | MOVE 1,0 116 | PUSHJ P,PUTCHAR 117 | MOVE 0,1 118 | POPJ P, 119 | 120 | # reads characters into INBUF - changes AC 0 1 2 121 | GETS: 122 | SETZM INP 123 | MOVE 1,INBUFBP 124 | SETZ 2, 125 | NEXTC: PUSHJ P,GETCH 126 | CAIN 0,"\n 127 | JRST GETSNL 128 | CAIN 0,25 129 | JRST GETSKL 130 | CAIN 0,"\b 131 | JRST GETSBS 132 | IDPB 0,1 133 | AOS 2 134 | PUSHJ P,PUTCHAR 135 | JRST NEXTC 136 | GETSKL: # kill line 137 | MOVEI 0,"\n 138 | PUSHJ P,PUTCHAR 139 | JRST GETS 140 | GETSBS: # backspace 141 | PUSHJ P,PUTCHAR 142 | MOVE 1,INBUFBP 143 | SOSGE 2 144 | SETZ 2, 145 | MOVE 0,2 146 | SOSGE 0 147 | JRST NEXTC 148 | IBP 1 149 | JRST .-3 150 | GETSNL: 151 | MOVEI 0,40 # space 152 | PUSHJ P,PUTCHAR 153 | SETZ 0, 154 | IDPB 0,1 155 | MOVEM 2,INBUF 156 | POPJ P, 157 | 158 | # 159 | # forth things 160 | # 161 | 162 | # Code field values 163 | ASM: 164 | AOS X 165 | JRST (X) 166 | 167 | DOCON: 168 | AOS X 169 | MOVE 0,(X) 170 | PUSH PP,0 171 | JRST NEXT 172 | 173 | DOVAR: 174 | AOS X 175 | PUSH PP,X 176 | JRST NEXT 177 | 178 | DOCOL: 179 | AOS X 180 | PUSH P,PC 181 | MOVE PC,X 182 | JRST NEXT 183 | 184 | # counterpart of DOCOL 185 | __EXIT: 0; 0,,4; ASCII "EXIT" 186 | _EXIT: ASM 187 | POP P,PC 188 | JRST NEXT 189 | 190 | # execute forth word at PC and increment PC 191 | NEXT: MOVE X,(PC) 192 | AOS PC 193 | MOVE 1,(X) 194 | JRST (1) 195 | 196 | # Dictionary 197 | LATEST: _LATEST 198 | HERE: END 199 | 200 | # parses one word from the input stream into the word buffer 201 | # skips if a word was read 202 | PARSEWORD: 203 | SETZM WORDBUF 204 | MOVE 0,INP 205 | MOVE 1,INBUFBP 206 | SOSGE 0 207 | JRST .+3 208 | IBP 1 209 | JRST .-3 210 | POP PP,2 # terminator 211 | MOVE 0,INP 212 | PWDELIM: 213 | ILDB 3,1 214 | AOS 0 215 | CAMLE 0,INBUF # check length 216 | JRST PWEND 217 | CAMN 3,2 # check for delimiter 218 | JRST PWDELIM 219 | MOVEM 0,INP # save beginning of word 220 | MOVE 4,WORDBUFBP 221 | PWCHAR: 222 | IDPB 3,4 223 | ILDB 3,1 224 | AOS 0 225 | CAMLE 0,INBUF # check length 226 | JRST .+3 227 | CAME 3,2 # check for delimiter 228 | JRST PWCHAR 229 | MOVE 1,INP 230 | SUB 1,0 231 | MOVMM 1,WORDBUF 232 | PWEND: 233 | MOVEM 0,INP 234 | SKIPE WORDBUF # skip one instruction if we have a word 235 | AOS (P) 236 | POPJ P, 237 | 238 | # find word AC 1 in dictionary, skip if found at return it in AC 1 239 | FIND: 240 | MOVE 2,LATEST 241 | SKIPA 242 | FINDNEXT: 243 | MOVE 2,(2) 244 | SKIPN 2 245 | POPJ P, # not found 246 | HRRZ 0,1(2) # length 247 | CAME 0,(1) 248 | JRST FINDNEXT 249 | MOVEI 3,1(1) # byte pointer of word to look up 250 | HRLI 3,440700 251 | MOVEI 4,2(2) # byte pointer of word in dictionary 252 | HRLI 4,440700 253 | FINDLOOP: 254 | ILDB 5,3 255 | ILDB 6,4 256 | CAME 5,6 257 | JRST FINDNEXT 258 | SOJG 0,FINDLOOP 259 | # found 260 | MOVE 1,2 261 | AOS (P) 262 | POPJ P, 263 | 264 | # go from dictionary entry AC 1 to code field 265 | TCFA: 266 | HRRZ 0,1(1) # length 267 | MOVEI 2,2(1) # byte pointer 268 | HRLI 2,440700 269 | IBP 2 270 | SOJG 0,.-1 271 | HRRZ 1,4 # get word address from byte pointer 272 | HLRZ 0,4 273 | CAIE 0,440700 # go to next word unless we're already there 274 | AOS 1 275 | POPJ P, 276 | 277 | # parse number in string AC 1, skip if number and return it in AC 0 278 | CHECKNUM: 279 | SETZ 0, 280 | MOVE 2,(1) # length 281 | AOS 1 282 | HRLI 1,440700 # byte pointer 283 | SETZ 4, # sign 284 | ILDB 3,1 285 | CAIE 3,"- 286 | JRST .+5 287 | SOSN 2 288 | POPJ P, 289 | AOS 4 290 | NUM1: ILDB 3,1 291 | CAIGE 3,"0 292 | POPJ P, 293 | CAILE 3,"9 294 | JRST .+3 295 | SUBI 3,"0 296 | JRST NUM2 297 | CAIGE 3,"A 298 | POPJ P, 299 | CAILE 3,"F 300 | JRST .+3 301 | SUBI 3,"A 302 | JRST NUM2 303 | CAIGE 3,"a 304 | POPJ P, 305 | CAILE 3,"f 306 | POPJ P, 307 | SUBI 3,"a 308 | NUM2: IMUL 0,BASE 309 | ADD 0,3 310 | SOJG 2,NUM1 311 | SKIPE 4 # negate if sign is set 312 | MOVN 0,0 313 | AOS (P) 314 | POPJ P, 315 | 316 | STATE: 0 # interpreter state (0 = interpreting, else compiling) 317 | 318 | __INTERPRET: __EXIT; 0,,9; ASCII "INTERPRET" 319 | _INTERPRET: ASM 320 | SKIPN INBUF 321 | PUSHJ P,GETS 322 | NEXTW: MOVEI 0,40 # space 323 | PUSH PP,0 324 | PUSHJ P,PARSEWORD 325 | JRST OK # end of line 326 | MOVEI 1,WORDBUF 327 | PUSHJ P,FIND 328 | JRST NUMBER 329 | HLR X,1(1) # get flags 330 | PUSHJ P,TCFA 331 | JUMPN X,.+3 # immediate 332 | SKIPE STATE 333 | JRST COMPW # compile word 334 | MOVE X,1 # interpret word 335 | MOVE 1,(X) 336 | JRST (1) 337 | COMPW: MOVE 2,HERE 338 | MOVEM 1,(2) 339 | AOS HERE 340 | JRST NEXTW 341 | NUMBER: MOVEI 1,WORDBUF 342 | PUSHJ P,CHECKNUM 343 | JRST PANIC 344 | SKIPE STATE 345 | JRST COMPN # compile number 346 | PUSH PP,0 # interpret number 347 | JRST NEXTW 348 | COMPN: MOVE 1,HERE 349 | MOVEI 2,_LITERAL 350 | MOVEM 2,(1) 351 | MOVEM 0,1(1) 352 | AOS HERE 353 | AOS HERE 354 | JRST NEXTW 355 | OK: SKIPE STATE 356 | JRST .+3 357 | MOVEI 0,{ASCII " ok\n\0"} 358 | JRST .+2 359 | MOVEI 0,{ASCII " compiled\n\0"} 360 | PUSHJ P,PUTS 361 | JRST NEXTW-1 362 | 363 | __QUIT: __INTERPRET; 0,,4; ASCII "QUIT" 364 | _QUIT: DOCOL 365 | { ASM; MOVE P,RSP; JRST NEXT } 366 | _INTERPRET 367 | _BRANCH 368 | -2 369 | 370 | __ABORT: __QUIT; 0,,5; ASCII "ABORT" 371 | _ABORT: DOCOL 372 | { ASM; MOVE PP,PSP; JRST NEXT } 373 | _QUIT 374 | 375 | __CREATE: __ABORT; 0,,6; ASCII "CREATE" 376 | _CREATE: ASM 377 | PUSHJ P,CREATE 378 | JRST NEXT 379 | 380 | CREATE: 381 | MOVEI 0,40 # space 382 | PUSH PP,0 383 | PUSHJ P,PARSEWORD 384 | JRST PANIC 385 | MOVE 1,LATEST 386 | MOVE 2,HERE 387 | MOVEM 1,(2) # link into dict 388 | MOVEM 2,LATEST 389 | MOVEI 1,WORDBUF # copy word 390 | HRRZ 0,0(1) # length 391 | MOVEM 0,1(2) 392 | MOVEI 3,1(1) # byte pointer of word buffer 393 | HRLI 3,440700 394 | MOVEI 4,2(2) # byte pointer of word in dictionary 395 | HRLI 4,440700 396 | ILDB 5,3 # copy chars 397 | IDPB 5,4 398 | SOJG 0,.-2 399 | HRRZ 1,4 # get word address from byte pointer 400 | HLRZ 0,4 401 | CAIE 0,440700 # go to next word unless we're already there 402 | AOS 1 403 | MOVEM 1,HERE 404 | POPJ P, 405 | 406 | __COLON: __CREATE; 0,,1; ASCII ":" 407 | _COLON: DOCOL 408 | _CREATE 409 | _LITERAL; DOCOL; _COMMA 410 | _RBRK 411 | _EXIT 412 | 413 | __SEMICOLON: __COLON; 1,,1; ASCII ";" 414 | _SEMICOLON: DOCOL 415 | _LITERAL; _EXIT; _COMMA 416 | _LBRK 417 | _EXIT 418 | 419 | __CONST: __SEMICOLON; 0,,8; ASCII "CONSTANT" 420 | _CONST: DOCOL 421 | _CREATE 422 | _LITERAL; DOCON; _COMMA 423 | _COMMA 424 | _EXIT 425 | 426 | __VAR: __CONST; 0,,8; ASCII "VARIABLE" 427 | _VAR: DOCOL 428 | _CREATE 429 | _LITERAL; DOVAR; _COMMA 430 | _LITERAL; 0; _COMMA 431 | _EXIT 432 | 433 | __BRANCH: __VAR; 0,,6; ASCII "BRANCH" 434 | _BRANCH: ASM 435 | MOVE 0,(PC) 436 | ADD PC,0 437 | JRST NEXT 438 | 439 | __ZBRANCH: __BRANCH; 0,,7; ASCII "0BRANCH" 440 | _ZBRANCH: ASM 441 | POP PP,1 442 | SKIPE 1 443 | JRST .+4 444 | MOVE 0,(PC) 445 | ADD PC,0 446 | JRST NEXT 447 | AOS PC 448 | JRST NEXT 449 | 450 | __LITERAL: __ZBRANCH; 0,,9; ASCII "(LITERAL)" 451 | _LITERAL: ASM 452 | MOVE 0,(PC) 453 | AOS PC 454 | PUSH PP,0 455 | JRST NEXT 456 | 457 | __COMMA: __LITERAL; 0,,1; ASCII "," 458 | _COMMA: ASM 459 | MOVE 1,HERE 460 | POP PP,0 461 | MOVEM 0,(1) 462 | AOS HERE 463 | JRST NEXT 464 | 465 | __LBRK: __COMMA; 0,,1; ASCII "[" 466 | _LBRK: ASM 467 | SETZM STATE 468 | JRST NEXT 469 | 470 | __RBRK: __LBRK; 0,,1; ASCII "]" 471 | _RBRK: ASM 472 | MOVEI 0,1 473 | MOVEM 0,STATE 474 | JRST NEXT 475 | 476 | __IMMED: __RBRK; 0,,9; ASCII "IMMEDIATE" 477 | _IMMED: ASM 478 | MOVE 1,LATEST 479 | MOVS 0,1 480 | XORM 0,1(1) 481 | JRST NEXT 482 | 483 | __DOT: __IMMED; 0,,1; ASCII "." 484 | _DOT: ASM 485 | POP PP,1 486 | PUSHJ P,PRINTNSP 487 | JRST NEXT 488 | 489 | __DOTS: __DOT; 0,,2; ASCII ".S" 490 | _DOTS: ASM 491 | MOVEI 0,"< 492 | PUSHJ P,PUTCHAR 493 | HRRZ 1,PP 494 | SUBI 1,PPDL-1 495 | MOVN 3,1 # loop counter 496 | PUSHJ P,PRINTN 497 | MOVEI 0,"> 498 | PUSHJ P,PUTCHAR 499 | SKIPN 3 500 | JRST NEXT # empty stack 501 | MOVS 3,3 # put counter in left word 502 | HRRI 3,PPDL 503 | MOVEI 0,40 504 | PUSHJ P,PUTCHAR 505 | MOVE 1,(3) 506 | PUSHJ P,PRINTNSP 507 | AOBJN 3,.-2 508 | JRST NEXT 509 | 510 | __DROP: __DOTS; 0,,4; ASCII "DROP" 511 | _DROP: ASM 512 | POP PP,0 513 | JRST NEXT 514 | 515 | __SWAP: __DROP; 0,,4; ASCII "SWAP" 516 | _SWAP: ASM 517 | POP PP,0 518 | EXCH 0,(PP) 519 | PUSH PP,0 520 | JRST NEXT 521 | 522 | __DUP: __SWAP; 0,,3; ASCII "DUP" 523 | _DUP: ASM 524 | PUSH PP,(PP) 525 | JRST NEXT 526 | 527 | __QDUP: __DUP; 0,,4; ASCII "?DUP" 528 | _QDUP: ASM 529 | SKIPE (PP) 530 | PUSH PP,(PP) 531 | JRST NEXT 532 | 533 | __OVER: __QDUP; 0,,4; ASCII "OVER" 534 | _OVER: ASM 535 | PUSH PP,-1(PP) 536 | JRST NEXT 537 | 538 | __ROT: __OVER; 0,,3; ASCII "ROT" 539 | _ROT: ASM 540 | POP PP,0 541 | POP PP,1 542 | POP PP,2 543 | PUSH PP,1 544 | PUSH PP,0 545 | PUSH PP,2 546 | JRST NEXT 547 | 548 | __NROT: __ROT; 0,,4; ASCII "-ROT" 549 | _NROT: ASM 550 | POP PP,0 551 | POP PP,1 552 | POP PP,2 553 | PUSH PP,0 554 | PUSH PP,2 555 | PUSH PP,1 556 | JRST NEXT 557 | 558 | __TOR: __NROT; 0,,2; ASCII ">R" 559 | _TOR: ASM 560 | POP PP,0 561 | PUSH P,0 562 | JRST NEXT 563 | 564 | __FROMR: __TOR; 0,,2; ASCII "R>" 565 | _FROMR: ASM 566 | POP P,0 567 | PUSH PP,0 568 | JRST NEXT 569 | 570 | __FETCHR: __FROMR; 0,,2; ASCII "R@" 571 | _FETCHR: ASM 572 | MOVE 0,(P) 573 | PUSH PP,0 574 | JRST NEXT 575 | 576 | __RSP: __FETCHR; 0,,4; ASCII "RSP@" 577 | _RSP: ASM 578 | PUSH PP,P 579 | JRST NEXT 580 | 581 | __INCR: __RSP; 0,,2; ASCII "1+" 582 | _INCR: ASM 583 | AOS (PP) 584 | JRST NEXT 585 | 586 | __DECR: __INCR; 0,,2; ASCII "1-" 587 | _DECR: ASM 588 | SOS (PP) 589 | JRST NEXT 590 | 591 | __PLUS: __DECR; 0,,1; ASCII "+" 592 | _PLUS: ASM 593 | POP PP,0 594 | ADDM 0,(PP) 595 | JRST NEXT 596 | 597 | __MINUS: __PLUS; 0,,1; ASCII "-" 598 | _MINUS: ASM 599 | POP PP,0 600 | POP PP,1 601 | SUB 1,0 602 | PUSH PP,1 603 | JRST NEXT 604 | 605 | __MUL: __MINUS; 0,,1; ASCII "*" 606 | _MUL: ASM 607 | POP PP,0 608 | IMULM 0,(PP) 609 | JRST NEXT 610 | 611 | __DIVMOD: __MUL; 0,,4; ASCII "/MOD" 612 | _DIVMOD: ASM 613 | POP PP,1 614 | POP PP,0 615 | IDIV 0,1 616 | PUSH PP,1 617 | PUSH PP,0 618 | JRST NEXT 619 | 620 | __DIV: __DIVMOD; 0,,1; ASCII "/" 621 | _DIV: ASM 622 | POP PP,1 623 | POP PP,0 624 | IDIV 0,1 625 | PUSH PP,0 626 | JRST NEXT 627 | 628 | __MOD: __DIV; 0,,3; ASCII "MOD" 629 | _MOD: ASM 630 | POP PP,1 631 | POP PP,0 632 | IDIV 0,1 633 | PUSH PP,1 634 | JRST NEXT 635 | 636 | __EQU: __MOD; 0,,1; ASCII "=" 637 | _EQU: ASM 638 | POP PP,0 639 | CAME 0,(PP) 640 | JRST FALSE 641 | TRUE: SETOM (PP) 642 | JRST NEXT 643 | FALSE: SETZM (PP) 644 | JRST NEXT 645 | 646 | __NEQU: __EQU; 0,,2; ASCII "<>" 647 | _NEQU: ASM 648 | POP PP,0 649 | CAMN 0,(PP) 650 | JRST FALSE 651 | JRST TRUE 652 | 653 | __LT: __NEQU; 0,,1; ASCII "<" 654 | _LT: ASM 655 | POP PP,0 656 | CAMG 0,(PP) 657 | JRST FALSE 658 | JRST TRUE 659 | 660 | __LE: __LT; 0,,2; ASCII "<=" 661 | _LE: ASM 662 | POP PP,0 663 | CAMGE 0,(PP) 664 | JRST FALSE 665 | JRST TRUE 666 | 667 | __GT: __LE; 0,,1; ASCII ">" 668 | _GT: ASM 669 | POP PP,0 670 | CAML 0,(PP) 671 | JRST FALSE 672 | JRST TRUE 673 | 674 | __GE: __GT; 0,,2; ASCII ">=" 675 | _GE: ASM 676 | POP PP,0 677 | CAMLE 0,(PP) 678 | JRST FALSE 679 | JRST TRUE 680 | 681 | __ZEQU: __GE; 0,,2; ASCII "0=" 682 | _ZEQU: ASM 683 | SKIPE (PP) 684 | JRST FALSE 685 | JRST TRUE 686 | 687 | __ZNEQU: __ZEQU; 0,,3; ASCII "0<>" 688 | _ZNEQU: ASM 689 | SKIPN (PP) 690 | JRST FALSE 691 | JRST TRUE 692 | 693 | __ZLT: __ZNEQU; 0,,2; ASCII "0<" 694 | _ZLT: ASM 695 | SKIPL (PP) 696 | JRST FALSE 697 | JRST TRUE 698 | 699 | __ZLE: __ZLT; 0,,3; ASCII "0<=" 700 | _ZLE: ASM 701 | SKIPLE (PP) 702 | JRST FALSE 703 | JRST TRUE 704 | 705 | __ZGT: __ZLE; 0,,2; ASCII "0>" 706 | _ZGT: ASM 707 | SKIPG (PP) 708 | JRST FALSE 709 | JRST TRUE 710 | 711 | __ZGE: __ZGT; 0,,3; ASCII "0>=" 712 | _ZGE: ASM 713 | SKIPGE (PP) 714 | JRST FALSE 715 | JRST TRUE 716 | 717 | __AND: __ZGE; 0,,3; ASCII "AND" 718 | _AND: ASM 719 | POP PP,0 720 | ANDM 0,(PP) 721 | JRST NEXT 722 | 723 | __OR: __AND; 0,,2; ASCII "OR" 724 | _OR: ASM 725 | POP PP,0 726 | IORM 0,(PP) 727 | JRST NEXT 728 | 729 | __XOR: __OR; 0,,3; ASCII "XOR" 730 | _XOR: ASM 731 | POP PP,0 732 | XORM 0,(PP) 733 | JRST NEXT 734 | 735 | __NOT: __XOR; 0,,3; ASCII "NOT" 736 | _NOT: ASM # same as 0= 737 | SKIPE (PP) 738 | JRST FALSE 739 | JRST TRUE 740 | 741 | __ABS: __NOT; 0,,3; ASCII "ABS" 742 | _ABS: ASM 743 | MOVM 0,(PP) 744 | MOVEM 0,(PP) 745 | JRST NEXT 746 | 747 | __NEG: __ABS; 0,,6; ASCII "NEGATE" 748 | _NEG: ASM 749 | MOVN 0,(PP) 750 | MOVEM 0,(PP) 751 | JRST NEXT 752 | 753 | __MIN: __NEG; 0,,3; ASCII "MIN" 754 | _MIN: ASM 755 | POP PP,0 756 | CAMGE 0,(PP) 757 | MOVEM 0,(PP) 758 | JRST NEXT 759 | 760 | __MAX: __MIN; 0,,3; ASCII "MAX" 761 | _MAX: ASM 762 | POP PP,0 763 | CAMLE 0,(PP) 764 | MOVEM 0,(PP) 765 | JRST NEXT 766 | 767 | __WORD: __MAX; 0,,4; ASCII "WORD" 768 | _WORD: ASM 769 | PUSHJ P,PARSEWORD 770 | JRST .+1 771 | PUSH PP,WORDBUF 772 | JRST NEXT 773 | 774 | __STORE: __WORD; 0,,1; ASCII "!" 775 | _STORE: ASM 776 | POP PP,1 777 | POP PP,0 778 | MOVEM 0,(1) 779 | JRST NEXT 780 | 781 | __PSTORE: __STORE; 0,,2; ASCII "+!" 782 | _PSTORE: ASM 783 | POP PP,1 784 | POP PP,0 785 | ADDM 0,(1) 786 | JRST NEXT 787 | 788 | __FETCH: __PSTORE; 0,,1; ASCII "@" 789 | _FETCH: ASM 790 | MOVE 1,(PP) 791 | MOVE 1,(1) 792 | MOVEM 1,(PP) 793 | JRST NEXT 794 | 795 | __HERE: __FETCH; 0,,4; ASCII "HERE" 796 | _HERE: DOCON; HERE 797 | 798 | __STATE: __HERE; 0,,5; ASCII "STATE" 799 | _STATE: DOCON; STATE 800 | 801 | __BASE: __STATE; 0,,4; ASCII "BASE" 802 | _BASE: DOCON; BASE 803 | 804 | __INP: __BASE; 0,,3; ASCII ">IN" 805 | _INP: DOCON; INP 806 | 807 | __IF: __INP; 1,,2; ASCII "IF" 808 | _IF: DOCOL 809 | _LITERAL; _ZBRANCH; _COMMA 810 | _HERE; _FETCH 811 | _LITERAL; 0; _COMMA 812 | _EXIT 813 | 814 | __THEN: __IF; 1,,4; ASCII "THEN" 815 | _THEN: DOCOL 816 | _DUP 817 | _HERE; _FETCH; _SWAP; _MINUS 818 | _SWAP; _STORE 819 | _EXIT 820 | 821 | __ELSE: __THEN; 1,,4; ASCII "ELSE" 822 | _ELSE: DOCOL 823 | _LITERAL; _BRANCH; _COMMA 824 | _HERE; _FETCH 825 | _LITERAL; 0; _COMMA 826 | _SWAP 827 | _DUP 828 | _HERE; _FETCH; _SWAP; _MINUS 829 | _SWAP; _STORE 830 | _EXIT 831 | 832 | __BEGIN: __ELSE; 1,,5; ASCII "BEGIN" 833 | _BEGIN: DOCOL 834 | _HERE; _FETCH 835 | _EXIT 836 | 837 | __AGAIN: __BEGIN; 1,,5; ASCII "AGAIN" 838 | _AGAIN: DOCOL 839 | _LITERAL; _BRANCH; _COMMA 840 | _HERE; _FETCH; _MINUS; _COMMA 841 | _EXIT 842 | 843 | __UNTIL: __AGAIN; 1,,5; ASCII "UNTIL" 844 | _UNTIL: DOCOL 845 | _LITERAL; _ZBRANCH; _COMMA 846 | _HERE; _FETCH; _MINUS; _COMMA 847 | _EXIT 848 | 849 | # same as IF really 850 | __WHILE: __UNTIL; 1,,5; ASCII "WHILE" 851 | _WHILE: DOCOL 852 | _LITERAL; _ZBRANCH; _COMMA 853 | _HERE; _FETCH 854 | _LITERAL; 0; _COMMA 855 | _EXIT 856 | 857 | __REPEAT: __WHILE; 1,,6; ASCII "REPEAT" 858 | _REPEAT: DOCOL 859 | _LITERAL; _BRANCH; _COMMA 860 | _SWAP 861 | _HERE; _FETCH; _MINUS; _COMMA 862 | _DUP 863 | _HERE; _FETCH; _SWAP; _MINUS 864 | _SWAP; _STORE 865 | _EXIT 866 | 867 | __DO: __REPEAT; 1,,2; ASCII "DO" 868 | _DO: DOCOL 869 | _LITERAL; _SWAP; _COMMA 870 | _LITERAL; _TOR; _COMMA 871 | _LITERAL; _TOR; _COMMA 872 | _HERE; _FETCH 873 | _EXIT 874 | 875 | # remove index and limit from return stack 876 | __UNLOOP: __DO; 0,,6; ASCII "UNLOOP" 877 | _UNLOOP: ASM 878 | POP P,0 879 | POP P,0 880 | JRST NEXT 881 | 882 | __LOOP: __UNLOOP; 1,,4; ASCII "LOOP" 883 | _LOOP: DOCOL 884 | _LITERAL; _FROMR; _COMMA # index 885 | _LITERAL; _INCR; _COMMA 886 | _LITERAL; _DUP; _COMMA 887 | _LITERAL; _FETCHR; _COMMA # limit 888 | _LITERAL; _GE; _COMMA # branch back if i >= limit is false 889 | _LITERAL; _SWAP; _COMMA # put index back on return stack 890 | _LITERAL; _TOR; _COMMA 891 | _LITERAL; _ZBRANCH; _COMMA 892 | _HERE; _FETCH; _MINUS; _COMMA 893 | _LITERAL; _UNLOOP; _COMMA 894 | _EXIT 895 | 896 | __PLUSLOOP: __LOOP; 1,,5; ASCII "+LOOP" 897 | _PLUSLOOP: DOCOL 898 | _LITERAL; _FROMR; _COMMA # index 899 | _LITERAL; _PLUS; _COMMA # only difference to above code 900 | _LITERAL; _DUP; _COMMA 901 | _LITERAL; _FETCHR; _COMMA # limit 902 | _LITERAL; _GE; _COMMA # branch back if i >= limit is false 903 | _LITERAL; _SWAP; _COMMA # put index back on return stack 904 | _LITERAL; _TOR; _COMMA 905 | _LITERAL; _ZBRANCH; _COMMA 906 | _HERE; _FETCH; _MINUS; _COMMA 907 | _LITERAL; _UNLOOP; _COMMA 908 | _EXIT 909 | 910 | __I: __PLUSLOOP; 0,,1; ASCII "I" 911 | _I: ASM 912 | MOVE 0,(P) 913 | PUSH PP,0 914 | JRST NEXT 915 | 916 | __J: __I; 0,,1; ASCII "J" 917 | _J: ASM 918 | MOVE 0,2(P) 919 | PUSH PP,0 920 | JRST NEXT 921 | 922 | __EMIT: __J; 0,,4; ASCII "EMIT" 923 | _EMIT: ASM 924 | POP PP,0 925 | PUSHJ P,PUTCHAR 926 | JRST NEXT 927 | 928 | __KEY: __EMIT; 0,,3; ASCII "KEY" 929 | _KEY: ASM 930 | PUSHJ P,GETCH 931 | PUSH PP,0 932 | JRST NEXT 933 | 934 | __CR: __KEY; 0,,2; ASCII "CR" 935 | _CR: DOCOL 936 | _LITERAL; "\n 937 | _EMIT 938 | _EXIT 939 | 940 | _LATEST: 941 | __SP: __KEY; 0,,5; ASCII "SPACE" 942 | _SP: DOCOL 943 | _LITERAL; 40 944 | _EMIT 945 | _EXIT 946 | 947 | END: 948 | -------------------------------------------------------------------------------- /as6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define SYMTABSZ 8000 8 | #define nil NULL 9 | 10 | typedef int64_t word; 11 | typedef uint64_t uword; 12 | typedef int32_t hword; 13 | 14 | #define WORD(l, r) (((l)&0777777) << 18 | ((r)&0777777)) 15 | #define LW(w) (((w) >> 18)&0777777) 16 | #define RW(w) ((w)&0777777) 17 | 18 | enum Valtype 19 | { 20 | Undef = 0, 21 | Abs, 22 | Op, 23 | Io, 24 | Asm, 25 | }; 26 | 27 | enum Toktype 28 | { 29 | Unused = 0, 30 | Eof, 31 | Symbol, 32 | Word, 33 | Newline, 34 | Space, 35 | Not, 36 | DQuote, 37 | Mod, 38 | And, 39 | LParen, 40 | RParen, 41 | Times, 42 | Plus, 43 | Comma, 44 | Cons, 45 | Minus, 46 | Period, 47 | Div, 48 | Colon, 49 | Semi, 50 | Less, 51 | Equal, 52 | Great, 53 | At, 54 | LBrack, 55 | RBrack, 56 | LBrace, 57 | Or, 58 | RBrace, 59 | 60 | /* only used as character classes */ 61 | Digit, 62 | Letter, 63 | }; 64 | 65 | typedef struct Value Value; 66 | struct Value 67 | { 68 | int type; 69 | word value; 70 | }; 71 | 72 | typedef struct Sym Sym; 73 | struct Sym 74 | { 75 | char name[24]; 76 | Value v; 77 | }; 78 | 79 | typedef struct Token Token; 80 | struct Token 81 | { 82 | int type; 83 | union { 84 | word w; 85 | Sym *s; 86 | }; 87 | }; 88 | 89 | typedef struct Section Section; 90 | struct Section 91 | { 92 | hword start; 93 | hword size; 94 | }; 95 | 96 | int chartab[] = { 97 | Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, 98 | Unused, Unused, Newline, Unused, Unused, Unused, Unused, Unused, 99 | Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, 100 | Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, 101 | Space, Not, DQuote, Unused, Unused, Mod, And, Unused, 102 | LParen, RParen, Times, Plus, Comma, Minus, Period, Div, 103 | Digit, Digit, Digit, Digit, Digit, Digit, Digit, Digit, 104 | Digit, Digit, Colon, Semi, Less, Equal, Great, Unused, 105 | At, Letter, Letter, Letter, Letter, Letter, Letter, Letter, 106 | Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, 107 | Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, 108 | Letter, Letter, Letter, LBrack, Unused, RBrack, Unused, Letter, 109 | Unused, Letter, Letter, Letter, Letter, Letter, Letter, Letter, 110 | Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, 111 | Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, 112 | Letter, Letter, Letter, LBrace, Or, RBrace, Unused, Unused 113 | }; 114 | #define CTYPE(c) chartab[(c)&0177] 115 | 116 | Sym *symtab[SYMTABSZ]; 117 | Sym syms[] = { 118 | { ".", Abs, 0 }, 119 | { "ASCII", Asm, 0 }, 120 | 121 | { "FSC", Op, 0132 }, 122 | { "IBP", Op, 0133 }, 123 | { "ILDB", Op, 0134 }, 124 | { "LDB", Op, 0135 }, 125 | { "IDPB", Op, 0136 }, 126 | { "DPB", Op, 0137 }, 127 | 128 | { "FAD", Op, 0140 }, 129 | { "FADL", Op, 0141 }, 130 | { "FADM", Op, 0142 }, 131 | { "FADB", Op, 0143 }, 132 | { "FADR", Op, 0144 }, 133 | { "FADRL", Op, 0145 }, 134 | { "FADRM", Op, 0146 }, 135 | { "FADRB", Op, 0147 }, 136 | { "FSB", Op, 0150 }, 137 | { "FSBL", Op, 0151 }, 138 | { "FSBM", Op, 0152 }, 139 | { "FSBB", Op, 0153 }, 140 | { "FSBR", Op, 0154 }, 141 | { "FSBRL", Op, 0155 }, 142 | { "FSBRM", Op, 0156 }, 143 | { "FSBRB", Op, 0157 }, 144 | { "FMP", Op, 0160 }, 145 | { "FMPL", Op, 0161 }, 146 | { "FMPM", Op, 0162 }, 147 | { "FMPB", Op, 0163 }, 148 | { "FMPR", Op, 0164 }, 149 | { "FMPRL", Op, 0165 }, 150 | { "FMPRM", Op, 0166 }, 151 | { "FMPRB", Op, 0167 }, 152 | { "FDV", Op, 0170 }, 153 | { "FDVL", Op, 0171 }, 154 | { "FDVM", Op, 0172 }, 155 | { "FDVB", Op, 0173 }, 156 | { "FDVR", Op, 0174 }, 157 | { "FDVRL", Op, 0175 }, 158 | { "FDVRM", Op, 0176 }, 159 | { "FDVRB", Op, 0177 }, 160 | 161 | { "MOVE", Op, 0200 }, 162 | { "MOVEI", Op, 0201 }, 163 | { "MOVEM", Op, 0202 }, 164 | { "MOVES", Op, 0203 }, 165 | { "MOVS", Op, 0204 }, 166 | { "MOVSI", Op, 0205 }, 167 | { "MOVSM", Op, 0206 }, 168 | { "MOVSS", Op, 0207 }, 169 | { "MOVN", Op, 0210 }, 170 | { "MOVNI", Op, 0211 }, 171 | { "MOVNM", Op, 0212 }, 172 | { "MOVNS", Op, 0213 }, 173 | { "MOVM", Op, 0214 }, 174 | { "MOVMI", Op, 0215 }, 175 | { "MOVMM", Op, 0216 }, 176 | { "MOVMS", Op, 0217 }, 177 | 178 | { "IMUL", Op, 0220 }, 179 | { "IMULI", Op, 0221 }, 180 | { "IMULM", Op, 0222 }, 181 | { "IMULB", Op, 0223 }, 182 | { "MUL", Op, 0224 }, 183 | { "MULI", Op, 0225 }, 184 | { "MULM", Op, 0226 }, 185 | { "MULB", Op, 0227 }, 186 | { "IDIV", Op, 0230 }, 187 | { "IDIVI", Op, 0231 }, 188 | { "IDIVM", Op, 0232 }, 189 | { "IDIVB", Op, 0233 }, 190 | { "DIV", Op, 0234 }, 191 | { "DIVI", Op, 0235 }, 192 | { "DIVM", Op, 0236 }, 193 | { "DIVB", Op, 0237 }, 194 | 195 | { "ASH", Op, 0240 }, 196 | { "ROT", Op, 0241 }, 197 | { "LSH", Op, 0242 }, 198 | { "ASHC", Op, 0244 }, 199 | { "ROTC", Op, 0245 }, 200 | { "LSHC", Op, 0246 }, 201 | 202 | { "EXCH", Op, 0250 }, 203 | { "BLT", Op, 0251 }, 204 | { "AOBJP", Op, 0252 }, 205 | { "AOBJN", Op, 0253 }, 206 | { "JRST", Op, 0254 }, 207 | { "JFCL", Op, 0255 }, 208 | { "XCT", Op, 0256 }, 209 | 210 | { "PUSHJ", Op, 0260 }, 211 | { "PUSH", Op, 0261 }, 212 | { "POP", Op, 0262 }, 213 | { "POPJ", Op, 0263 }, 214 | { "JSR", Op, 0264 }, 215 | { "JSP", Op, 0265 }, 216 | { "JSA", Op, 0266 }, 217 | { "JRA", Op, 0267 }, 218 | 219 | { "ADD", Op, 0270 }, 220 | { "ADDI", Op, 0271 }, 221 | { "ADDM", Op, 0272 }, 222 | { "ADDB", Op, 0273 }, 223 | { "SUB", Op, 0274 }, 224 | { "SUBI", Op, 0275 }, 225 | { "SUBM", Op, 0276 }, 226 | { "SUBB", Op, 0277 }, 227 | 228 | { "CAI", Op, 0300 }, 229 | { "CAIL", Op, 0301 }, 230 | { "CAIE", Op, 0302 }, 231 | { "CAILE", Op, 0303 }, 232 | { "CAIA", Op, 0304 }, 233 | { "CAIGE", Op, 0305 }, 234 | { "CAIN", Op, 0306 }, 235 | { "CAIG", Op, 0307 }, 236 | { "CAM", Op, 0310 }, 237 | { "CAML", Op, 0311 }, 238 | { "CAME", Op, 0312 }, 239 | { "CAMLE", Op, 0313 }, 240 | { "CAMA", Op, 0314 }, 241 | { "CAMGE", Op, 0315 }, 242 | { "CAMN", Op, 0316 }, 243 | { "CAMG", Op, 0317 }, 244 | { "JUMP", Op, 0320 }, 245 | { "JUMPL", Op, 0321 }, 246 | { "JUMPE", Op, 0322 }, 247 | { "JUMPLE",Op, 0323 }, 248 | { "JUMPA", Op, 0324 }, 249 | { "JUMPGE",Op, 0325 }, 250 | { "JUMPN", Op, 0326 }, 251 | { "JUMPG", Op, 0327 }, 252 | { "SKIP", Op, 0330 }, 253 | { "SKIPL", Op, 0331 }, 254 | { "SKIPE", Op, 0332 }, 255 | { "SKIPLE",Op, 0333 }, 256 | { "SKIPA", Op, 0334 }, 257 | { "SKIPGE",Op, 0335 }, 258 | { "SKIPN", Op, 0336 }, 259 | { "SKIPG", Op, 0337 }, 260 | { "AOJ", Op, 0340 }, 261 | { "AOJL", Op, 0341 }, 262 | { "AOJE", Op, 0342 }, 263 | { "AOJLE", Op, 0343 }, 264 | { "AOJA", Op, 0344 }, 265 | { "AOJGE", Op, 0345 }, 266 | { "AOJN", Op, 0346 }, 267 | { "AOJG", Op, 0347 }, 268 | { "AOS", Op, 0350 }, 269 | { "AOSL", Op, 0351 }, 270 | { "AOSE", Op, 0352 }, 271 | { "AOSLE", Op, 0353 }, 272 | { "AOSA", Op, 0354 }, 273 | { "AOSGE", Op, 0355 }, 274 | { "AOSN", Op, 0356 }, 275 | { "AOSG", Op, 0357 }, 276 | { "SOJ", Op, 0360 }, 277 | { "SOJL", Op, 0361 }, 278 | { "SOJE", Op, 0362 }, 279 | { "SOJLE", Op, 0363 }, 280 | { "SOJA", Op, 0364 }, 281 | { "SOJGE", Op, 0365 }, 282 | { "SOJN", Op, 0366 }, 283 | { "SOJG", Op, 0367 }, 284 | { "SOS", Op, 0370 }, 285 | { "SOSL", Op, 0371 }, 286 | { "SOSE", Op, 0372 }, 287 | { "SOSLE", Op, 0373 }, 288 | { "SOSA", Op, 0374 }, 289 | { "SOSGE", Op, 0375 }, 290 | { "SOSN", Op, 0376 }, 291 | { "SOSG", Op, 0377 }, 292 | 293 | { "SETZ", Op, 0400 }, 294 | { "SETZI", Op, 0401 }, 295 | { "SETZM", Op, 0402 }, 296 | { "SETZB", Op, 0403 }, 297 | { "AND", Op, 0404 }, 298 | { "ANDI", Op, 0405 }, 299 | { "ANDM", Op, 0406 }, 300 | { "ANDB", Op, 0407 }, 301 | { "ANDCA", Op, 0410 }, 302 | { "ANDCAI",Op, 0411 }, 303 | { "ANDCAM",Op, 0412 }, 304 | { "ANDCAB",Op, 0413 }, 305 | { "SETM", Op, 0414 }, 306 | { "SETMI", Op, 0415 }, 307 | { "SETMM", Op, 0416 }, 308 | { "SETMB", Op, 0417 }, 309 | { "ANDCM", Op, 0420 }, 310 | { "ANDCMI",Op, 0421 }, 311 | { "ANDCMM",Op, 0422 }, 312 | { "ANDCMB",Op, 0423 }, 313 | { "SETA", Op, 0424 }, 314 | { "SETAI", Op, 0425 }, 315 | { "SETAM", Op, 0426 }, 316 | { "SETAB", Op, 0427 }, 317 | { "XOR", Op, 0430 }, 318 | { "XORI", Op, 0431 }, 319 | { "XORM", Op, 0432 }, 320 | { "XORB", Op, 0433 }, 321 | { "IOR", Op, 0434 }, 322 | { "IORI", Op, 0435 }, 323 | { "IORM", Op, 0436 }, 324 | { "IORB", Op, 0437 }, 325 | { "ANDCB", Op, 0440 }, 326 | { "ANDCBI",Op, 0441 }, 327 | { "ANDCBM",Op, 0442 }, 328 | { "ANDCBB",Op, 0443 }, 329 | { "EQV", Op, 0444 }, 330 | { "EQVI", Op, 0445 }, 331 | { "EQVM", Op, 0446 }, 332 | { "EQVB", Op, 0447 }, 333 | { "SETCA", Op, 0450 }, 334 | { "SETCAI",Op, 0451 }, 335 | { "SETCAM",Op, 0452 }, 336 | { "SETCAB",Op, 0453 }, 337 | { "ORCA", Op, 0454 }, 338 | { "ORCAI", Op, 0455 }, 339 | { "ORCAM", Op, 0456 }, 340 | { "ORCAB", Op, 0457 }, 341 | { "SETCM", Op, 0460 }, 342 | { "SETCMI",Op, 0461 }, 343 | { "SETCMM",Op, 0462 }, 344 | { "SETCMB",Op, 0463 }, 345 | { "ORCM", Op, 0464 }, 346 | { "ORCMI", Op, 0465 }, 347 | { "ORCMM", Op, 0466 }, 348 | { "ORCMB", Op, 0467 }, 349 | { "ORCB", Op, 0470 }, 350 | { "ORCBI", Op, 0471 }, 351 | { "ORCBM", Op, 0472 }, 352 | { "ORCBB", Op, 0473 }, 353 | { "SETO", Op, 0474 }, 354 | { "SETOI", Op, 0475 }, 355 | { "SETOM", Op, 0476 }, 356 | { "SETOB", Op, 0477 }, 357 | 358 | { "HLL", Op, 0500 }, 359 | { "HLLI", Op, 0501 }, 360 | { "HLLM", Op, 0502 }, 361 | { "HLLS", Op, 0503 }, 362 | { "HRL", Op, 0504 }, 363 | { "HRLI", Op, 0505 }, 364 | { "HRLM", Op, 0506 }, 365 | { "HRLS", Op, 0507 }, 366 | { "HLLZ", Op, 0510 }, 367 | { "HLLZI", Op, 0511 }, 368 | { "HLLZM", Op, 0512 }, 369 | { "HLLZS", Op, 0513 }, 370 | { "HRLZ", Op, 0514 }, 371 | { "HRLZI", Op, 0515 }, 372 | { "HRLZM", Op, 0516 }, 373 | { "HRLZS", Op, 0517 }, 374 | { "HLLO", Op, 0520 }, 375 | { "HLLOI", Op, 0521 }, 376 | { "HLLOM", Op, 0522 }, 377 | { "HLLOS", Op, 0523 }, 378 | { "HRLO", Op, 0524 }, 379 | { "HRLOI", Op, 0525 }, 380 | { "HRLOM", Op, 0526 }, 381 | { "HRLOS", Op, 0527 }, 382 | { "HLLE", Op, 0530 }, 383 | { "HLLEI", Op, 0531 }, 384 | { "HLLEM", Op, 0532 }, 385 | { "HLLES", Op, 0533 }, 386 | { "HRLE", Op, 0534 }, 387 | { "HRLEI", Op, 0535 }, 388 | { "HRLEM", Op, 0536 }, 389 | { "HRLES", Op, 0537 }, 390 | { "HRR", Op, 0540 }, 391 | { "HRRI", Op, 0541 }, 392 | { "HRRM", Op, 0542 }, 393 | { "HRRS", Op, 0543 }, 394 | { "HLR", Op, 0544 }, 395 | { "HLRI", Op, 0545 }, 396 | { "HLRM", Op, 0546 }, 397 | { "HLRS", Op, 0547 }, 398 | { "HRRZ", Op, 0550 }, 399 | { "HRRZI", Op, 0551 }, 400 | { "HRRZM", Op, 0552 }, 401 | { "HRRZS", Op, 0553 }, 402 | { "HLRZ", Op, 0554 }, 403 | { "HLRZI", Op, 0555 }, 404 | { "HLRZM", Op, 0556 }, 405 | { "HLRZS", Op, 0557 }, 406 | { "HRRO", Op, 0560 }, 407 | { "HRROI", Op, 0561 }, 408 | { "HRROM", Op, 0562 }, 409 | { "HRROS", Op, 0563 }, 410 | { "HLRO", Op, 0564 }, 411 | { "HLROI", Op, 0565 }, 412 | { "HLROM", Op, 0566 }, 413 | { "HLROS", Op, 0567 }, 414 | { "HRRE", Op, 0570 }, 415 | { "HRREI", Op, 0571 }, 416 | { "HRREM", Op, 0572 }, 417 | { "HRRES", Op, 0573 }, 418 | { "HLRE", Op, 0574 }, 419 | { "HLREI", Op, 0575 }, 420 | { "HLREM", Op, 0576 }, 421 | { "HLRES", Op, 0577 }, 422 | 423 | { "TRN", Op, 0600 }, 424 | { "TLN", Op, 0601 }, 425 | { "TRNE", Op, 0602 }, 426 | { "TLNE", Op, 0603 }, 427 | { "TRNA", Op, 0604 }, 428 | { "TLNA", Op, 0605 }, 429 | { "TRNN", Op, 0606 }, 430 | { "TLNN", Op, 0607 }, 431 | { "TDN", Op, 0610 }, 432 | { "TSN", Op, 0611 }, 433 | { "TDNE", Op, 0612 }, 434 | { "TSNE", Op, 0613 }, 435 | { "TDNA", Op, 0614 }, 436 | { "TSNA", Op, 0615 }, 437 | { "TDNN", Op, 0616 }, 438 | { "TSNN", Op, 0617 }, 439 | { "TRZ", Op, 0620 }, 440 | { "TLZ", Op, 0621 }, 441 | { "TRZE", Op, 0622 }, 442 | { "TLZE", Op, 0623 }, 443 | { "TRZA", Op, 0624 }, 444 | { "TLZA", Op, 0625 }, 445 | { "TRZN", Op, 0626 }, 446 | { "TLZN", Op, 0627 }, 447 | { "TDZ", Op, 0630 }, 448 | { "TSZ", Op, 0631 }, 449 | { "TDZE", Op, 0632 }, 450 | { "TSZE", Op, 0633 }, 451 | { "TDZA", Op, 0634 }, 452 | { "TSZA", Op, 0635 }, 453 | { "TDZN", Op, 0636 }, 454 | { "TSZN", Op, 0637 }, 455 | { "TRC", Op, 0640 }, 456 | { "TLC", Op, 0641 }, 457 | { "TRCE", Op, 0642 }, 458 | { "TLCE", Op, 0643 }, 459 | { "TRCA", Op, 0644 }, 460 | { "TLCA", Op, 0645 }, 461 | { "TRCN", Op, 0646 }, 462 | { "TLCN", Op, 0647 }, 463 | { "TDC", Op, 0650 }, 464 | { "TSC", Op, 0651 }, 465 | { "TDCE", Op, 0652 }, 466 | { "TSCE", Op, 0653 }, 467 | { "TDCA", Op, 0654 }, 468 | { "TSCA", Op, 0655 }, 469 | { "TDCN", Op, 0656 }, 470 | { "TSCN", Op, 0657 }, 471 | { "TRO", Op, 0660 }, 472 | { "TLO", Op, 0661 }, 473 | { "TROE", Op, 0662 }, 474 | { "TLOE", Op, 0663 }, 475 | { "TROA", Op, 0664 }, 476 | { "TLOA", Op, 0665 }, 477 | { "TRON", Op, 0666 }, 478 | { "TLON", Op, 0667 }, 479 | { "TDO", Op, 0670 }, 480 | { "TSO", Op, 0671 }, 481 | { "TDOE", Op, 0672 }, 482 | { "TSOE", Op, 0673 }, 483 | { "TDOA", Op, 0674 }, 484 | { "TSOA", Op, 0675 }, 485 | { "TDON", Op, 0676 }, 486 | { "TSON", Op, 0677 }, 487 | 488 | { "BLKI", Io, 070000 }, 489 | { "BLKO", Io, 070010 }, 490 | { "DATAI", Io, 070004 }, 491 | { "DATAO", Io, 070014 }, 492 | { "CONO", Io, 070020 }, 493 | { "CONI", Io, 070024 }, 494 | { "CONSZ", Io, 070030 }, 495 | { "CONSO", Io, 070034 }, 496 | { "", 0, 0 } 497 | }; 498 | 499 | hword assemble(void); 500 | 501 | int pass2; 502 | int error; 503 | word origin; 504 | word mem[01000000]; 505 | 506 | #define MAXSECT 100 /* increase if necessary */ 507 | Section sects[MAXSECT]; 508 | int nsect; 509 | hword nextdot; 510 | 511 | FILE *tokf; 512 | FILE *wf; 513 | FILE *outf; 514 | 515 | int nextc; 516 | int toksp; 517 | Token tokstk[2]; 518 | Sym *dot; 519 | 520 | #define PUSHT(t) tokstk[toksp++] = (t) 521 | 522 | void 523 | putw10(word w, FILE *f) 524 | { 525 | int i; 526 | w &= 0777777777777; 527 | for(i = 5; i >= 0; i--) 528 | putc(((w>>i*6)&077)|0200, f); 529 | } 530 | 531 | void 532 | writeblock(word origin, word count) 533 | { 534 | int i; 535 | word chksm; 536 | word w; 537 | 538 | chksm = 0; 539 | putw10(w = WORD(-count, origin-1), outf); 540 | chksm += w; 541 | for(i = 0; i < count; i++){ 542 | chksm += mem[i+origin]; 543 | putw10(mem[i+origin], outf); 544 | } 545 | putw10(-chksm, outf); 546 | } 547 | 548 | int 549 | ch(void) 550 | { 551 | int c; 552 | if(nextc){ 553 | c = nextc; 554 | nextc = 0; 555 | return c; 556 | } 557 | c = getchar(); 558 | tail: 559 | if(c == '#'){ 560 | while(c = getchar(), c != '\n') 561 | if(c == EOF) return c; 562 | goto tail; 563 | } 564 | if(c == '\t' || c == '\r') 565 | c = ' '; 566 | return c; 567 | } 568 | 569 | int 570 | chsp(void) 571 | { 572 | int c; 573 | while(c = ch(), c == ' '); 574 | return c; 575 | } 576 | 577 | int 578 | hash(char *s) 579 | { 580 | int hsh; 581 | hsh = 0; 582 | for(; *s != '\0'; s++) 583 | hsh += *s; 584 | return hsh % SYMTABSZ; 585 | } 586 | 587 | Sym** 588 | findsym(char *name) 589 | { 590 | int hsh; 591 | char *p; 592 | Sym **s; 593 | 594 | hsh = hash(name); 595 | s = &symtab[hsh]; 596 | for(;;){ 597 | if(*s == nil || 598 | strncmp((*s)->name, name, 24) == 0) 599 | return s; 600 | s++; 601 | if(s == &symtab[SYMTABSZ]) 602 | s = symtab; 603 | if(s == &symtab[hsh]){ 604 | fprintf(stderr, "symbol table full\n"); 605 | exit(1); 606 | } 607 | } 608 | } 609 | 610 | Sym* 611 | getsym(char *name) 612 | { 613 | Sym **p; 614 | p = findsym(name); 615 | if(*p) 616 | return *p; 617 | *p = malloc(sizeof(Sym)); 618 | strncpy((*p)->name, name, 24); 619 | (*p)->v.type = Undef; 620 | (*p)->v.value = 0; 621 | return *p; 622 | } 623 | 624 | word 625 | number(void) 626 | { 627 | int c; 628 | word n, oct, dec; 629 | int sign; 630 | 631 | sign = 1; 632 | if(c = ch(), c == '-') 633 | sign = -1; 634 | else 635 | nextc = c; 636 | oct = dec = 0; 637 | while(c = ch(), CTYPE(c) == Digit){ 638 | oct = (oct << 3) | (c-'0'); 639 | dec = dec*10 + (c-'0'); 640 | } 641 | if(c == '.') 642 | n = dec; 643 | else{ 644 | n = oct; 645 | nextc = c; 646 | } 647 | return (n*sign)&0777777777777; 648 | } 649 | 650 | int 651 | strchar(int delim) 652 | { 653 | int c; 654 | c = getchar(); 655 | if(delim && c == delim) 656 | return 0400; 657 | if(c != '\\') 658 | return c; 659 | c = getchar(); 660 | switch(c){ 661 | case 'b': 662 | c = '\b'; 663 | break; 664 | 665 | case 'n': 666 | c = '\n'; 667 | break; 668 | 669 | case 'r': 670 | c = '\r'; 671 | break; 672 | 673 | case '\\': 674 | c = '\\'; 675 | break; 676 | 677 | case '0': 678 | c = 0; 679 | break; 680 | } 681 | return c; 682 | } 683 | 684 | Token 685 | token(void) 686 | { 687 | char name[24]; 688 | char *p; 689 | int c; 690 | Token t; 691 | 692 | if(toksp){ 693 | t = tokstk[--toksp]; 694 | return t; 695 | } 696 | if(pass2){ 697 | fread(&t, sizeof(t), 1, tokf); 698 | return t; 699 | } 700 | c = chsp(); 701 | if(c == EOF) 702 | t.type = Eof; 703 | else 704 | switch(CTYPE(c)){ 705 | case Period: 706 | case Letter: 707 | p = name; 708 | do{ 709 | if(p < name+23) 710 | *p++ = toupper(c); 711 | }while(c = ch(), CTYPE(c) == Letter || 712 | CTYPE(c) == Period || 713 | CTYPE(c) == Digit); 714 | nextc = c; 715 | *p++ = '\0'; 716 | t.type = Symbol; 717 | t.s = getsym(name); 718 | break; 719 | 720 | case Digit: 721 | nextc = c; 722 | t.type = Word; 723 | t.w = number(); 724 | break; 725 | 726 | case DQuote: 727 | t.type = Word; 728 | t.w = strchar(0); 729 | break; 730 | 731 | case Comma: 732 | c = chsp(); 733 | if(CTYPE(c) == Comma) 734 | t.type = Cons; 735 | else{ 736 | t.type = Comma; 737 | nextc = c; 738 | } 739 | break; 740 | 741 | case Unused: 742 | fprintf(stderr, "unknown char: %c\n", c); 743 | break; 744 | 745 | default: 746 | t.type = CTYPE(c); 747 | break; 748 | } 749 | fwrite(&t, sizeof(t), 1, tokf); 750 | return t; 751 | } 752 | 753 | void 754 | directive(int type) 755 | { 756 | uword w; 757 | int c, i, s; 758 | 759 | if(type == 0){ /* ascii */ 760 | /* save ascii words in word file because they're not tokens */ 761 | if(!pass2){ 762 | c = chsp(); 763 | if(c != '"'){ 764 | fprintf(stderr, "\" expected\n"); 765 | return; 766 | } 767 | w = 0; 768 | i = 0; 769 | s = 29; 770 | while(c = strchar('"'), c != 0400 && c != EOF){ 771 | c &= 0177; 772 | w = w | ((uword)c << s); 773 | s -= 7; 774 | if(++i == 5){ 775 | fwrite(&w, sizeof(w), 1, wf); 776 | dot->v.value++; 777 | i = 0; 778 | s = 29; 779 | w = 0; 780 | } 781 | } 782 | if(i){ 783 | fwrite(&w, sizeof(w), 1, wf); 784 | dot->v.value++; 785 | } 786 | w = ~0; 787 | fwrite(&w, sizeof(w), 1, wf); 788 | dot->v.value++; 789 | }else{ 790 | while(fread(&w, sizeof(w), 1, wf), w != ~0) 791 | mem[dot->v.value++] = w; 792 | } 793 | } 794 | } 795 | 796 | Value 797 | apply(int op, Value v1, Value v2) 798 | { 799 | switch(op){ 800 | case Not: 801 | v1.value |= ~v2.value; 802 | break; 803 | 804 | case Plus: 805 | v1.value += v2.value; 806 | break; 807 | 808 | case Minus: 809 | v1.value -= v2.value; 810 | break; 811 | 812 | case Times: 813 | v1.value *= v2.value; 814 | break; 815 | 816 | case Div: 817 | v1.value /= v2.value; 818 | break; 819 | 820 | case Mod: 821 | v1.value %= v2.value; 822 | break; 823 | 824 | case And: 825 | v1.value &= v2.value; 826 | break; 827 | 828 | case Or: 829 | v1.value |= v2.value; 830 | break; 831 | 832 | case Less: 833 | v1.value <<= v2.value; 834 | break; 835 | 836 | case Great: 837 | v1.value >>= v2.value; 838 | break; 839 | 840 | case Cons: 841 | v1.value = WORD(v1.value, v2.value); 842 | break; 843 | 844 | default: 845 | fprintf(stderr, "unknown op %d\n", op); 846 | return v2; 847 | } 848 | v1.value &= 0777777777777; 849 | return v1; 850 | } 851 | 852 | Value 853 | expr(void) 854 | { 855 | Token t; 856 | int op; 857 | Value v, v2; 858 | hword savedot; 859 | 860 | v.type = Abs; 861 | v.value = 0; 862 | op = Plus; 863 | 864 | /* TODO: just accept possible tokens */ 865 | while(t = token(), 866 | t.type != RBrack && t.type != RBrace && t.type != Comma && 867 | t.type != LParen && t.type != RParen && 868 | t.type != Newline && t.type != Semi){ 869 | switch(t.type){ 870 | case Word: 871 | v2.type = Abs; 872 | v2.value = t.w; 873 | v = apply(op, v, v2); 874 | op = Plus; 875 | break; 876 | 877 | case Symbol: 878 | v = apply(op, v, t.s->v); 879 | op = Plus; 880 | break; 881 | 882 | case LBrack: 883 | v2 = expr(); 884 | t = token(); 885 | if(t.type != RBrack){ 886 | fprintf(stderr, "']' expected\n"); 887 | error = 1; 888 | PUSHT(t); 889 | } 890 | v = apply(op, v, v2); 891 | op = Plus; 892 | break; 893 | 894 | case LBrace: 895 | v2.type = Abs; 896 | savedot = dot->v.value; 897 | v2.value = assemble(); 898 | dot->v.value = savedot; 899 | t = token(); 900 | if(t.type != RBrace){ 901 | fprintf(stderr, "'}' expected\n"); 902 | error = 1; 903 | PUSHT(t); 904 | } 905 | v = apply(op, v, v2); 906 | op = Plus; 907 | break; 908 | 909 | case Not: 910 | case Plus: 911 | case Minus: 912 | case Times: 913 | case Div: 914 | case Mod: 915 | case And: 916 | case Or: 917 | case Less: 918 | case Great: 919 | case Cons: 920 | op = t.type; 921 | break; 922 | 923 | default: 924 | fprintf(stderr, "can't parse expr %d\n", t.type); 925 | error = 1; 926 | v.type = Abs; 927 | v.value = 0; 928 | } 929 | } 930 | PUSHT(t); 931 | return v; 932 | } 933 | 934 | word 935 | opline(void) 936 | { 937 | word inst; 938 | word op, ac, i, x, y; 939 | word w; 940 | Token t; 941 | Value v; 942 | int type; 943 | 944 | type = 0; 945 | ac = i = x = y = 0; 946 | t = token(); 947 | if(t.s->v.type == Op){ 948 | op = t.s->v.value & 0777; 949 | }else if(t.s->v.type == Io){ 950 | type = 1; 951 | op = t.s->v.value & 077774; 952 | }else{ 953 | fprintf(stderr, "expected opcode\n"); 954 | error = 1; 955 | } 956 | 957 | /* So many gotos, sorry Edsger */ 958 | t = token(); 959 | if(t.type == At){ 960 | i = 1; 961 | t = token(); 962 | goto Y; 963 | } 964 | if(t.type == LParen) 965 | goto X; 966 | if(t.type == Newline || t.type == Semi){ 967 | PUSHT(t); 968 | goto end; 969 | } 970 | PUSHT(t); /* has to be AC or Y now */ 971 | w = expr().value; 972 | t = token(); 973 | if(t.type == Comma) 974 | ac = w & (type == 0 ? 017 : 0774); 975 | else{ 976 | y = w & 0777777; 977 | if(t.type == LParen) 978 | goto X; 979 | PUSHT(t); 980 | goto end; 981 | } 982 | t = token(); 983 | if(t.type == Newline || t.type == Semi){ 984 | PUSHT(t); 985 | goto end; 986 | } 987 | if(t.type == At){ 988 | i = 1; 989 | t = token(); 990 | } 991 | Y: 992 | if(t.type != LParen){ 993 | PUSHT(t); 994 | y = expr().value & 0777777; 995 | t = token(); 996 | if(t.type == LParen) 997 | goto X; 998 | PUSHT(t); 999 | }else{ 1000 | X: 1001 | x = expr().value & 017; 1002 | t = token(); 1003 | if(t.type != RParen){ 1004 | fprintf(stderr, ") expected\n"); 1005 | error = 1; 1006 | PUSHT(t); 1007 | } 1008 | } 1009 | 1010 | end: 1011 | if(type == 0) 1012 | inst = op << 27 | 1013 | ac << 23 | 1014 | i << 22 | 1015 | x << 18 | 1016 | y; 1017 | else{ 1018 | inst = op << 21 | 1019 | ac << 24 | /* this is correct */ 1020 | i << 22 | 1021 | x << 18 | 1022 | y; 1023 | } 1024 | // printf("inst: %lo\n", inst); 1025 | return inst; 1026 | } 1027 | 1028 | hword 1029 | assemble(void) 1030 | { 1031 | Token t, tt; 1032 | Section *sect; 1033 | sect = §s[nsect++]; 1034 | if(sect == §s[MAXSECT]){ 1035 | fprintf(stderr, "ran out of sections\n"); 1036 | exit(1); 1037 | } 1038 | dot->v.value = sect->start; 1039 | // printf("section %d %o %o\n", nsect, sect->start, sect->size); 1040 | 1041 | while(t = token(), t.type != Eof && t.type != RBrace){ 1042 | switch(t.type){ 1043 | case Symbol: 1044 | if(t.s->v.type == Asm){ 1045 | directive(t.s->v.value); 1046 | t = token(); 1047 | break; 1048 | } 1049 | if(t.s->v.type == Op || 1050 | t.s->v.type == Io){ 1051 | PUSHT(t); 1052 | mem[dot->v.value] = opline(); 1053 | dot->v.value++; 1054 | t = token(); 1055 | break; 1056 | } 1057 | tt = token(); 1058 | if(tt.type == Colon){ 1059 | // if(t.s->v.type != Undef && 1060 | // t.s->v.value != dot->v.value) 1061 | // fprintf(stderr, "redefining %s\n", 1062 | // t.s->name); 1063 | t.s->v = dot->v; 1064 | continue; 1065 | }else if(tt.type == Equal){ 1066 | t.s->v = expr(); 1067 | t = token(); 1068 | }else{ 1069 | PUSHT(tt); 1070 | goto exp; 1071 | } 1072 | break; 1073 | 1074 | exp: 1075 | case Not: 1076 | case LBrace: 1077 | case LBrack: 1078 | case Minus: 1079 | case Word: 1080 | PUSHT(t); 1081 | mem[dot->v.value++] = expr().value; 1082 | t = token(); 1083 | break; 1084 | 1085 | default: 1086 | if(t.type != Newline && t.type != Semi){ 1087 | fprintf(stderr, "can't parse %d\n", t.type); 1088 | error = 1; 1089 | } 1090 | } 1091 | 1092 | // if(!pass2) 1093 | // printf("statement %d\n", t.type); 1094 | if(t.type == RBrace) 1095 | break; 1096 | if(t.type != Newline && t.type != Semi){ 1097 | PUSHT(t); 1098 | fprintf(stderr, "statement not ended %d\n", t.type); 1099 | error = 1; 1100 | while(t.type != Newline && t.type != Semi) 1101 | t = token(); 1102 | } 1103 | } 1104 | PUSHT(t); 1105 | 1106 | if(!pass2){ 1107 | sect->size = dot->v.value - sect->start; 1108 | sect->start = nextdot; 1109 | nextdot += sect->size; 1110 | // printf("size: %o %o\n", sect->size, sect->start); 1111 | } 1112 | return sect->start; 1113 | } 1114 | 1115 | void 1116 | dumpsymbols(void) 1117 | { 1118 | int i; 1119 | for(i = 0; i < SYMTABSZ; i++) 1120 | if(symtab[i] && symtab[i]->v.type != Op && 1121 | symtab[i]->v.type != Io) 1122 | fprintf(stderr, "%s %o %lo\n", symtab[i]->name, 1123 | symtab[i]->v.type, symtab[i]->v.value); 1124 | } 1125 | 1126 | void 1127 | dumpmem(word start, word end) 1128 | { 1129 | for(; start < end; start++) 1130 | if(mem[start]) 1131 | printf("%lo: %lo\n", start, mem[start]); 1132 | } 1133 | 1134 | void 1135 | initsyms(void) 1136 | { 1137 | int hsh; 1138 | Sym *s, **sp; 1139 | 1140 | for(s = syms; s->name[0]; s++){ 1141 | sp = findsym(s->name); 1142 | *sp = s; 1143 | } 1144 | dot = getsym("."); 1145 | } 1146 | 1147 | int 1148 | main(int argc, char *argv[]) 1149 | { 1150 | Section *s; 1151 | Sym **start; 1152 | hword blkstart, blksize; 1153 | 1154 | origin = 01000; 1155 | initsyms(); 1156 | 1157 | /* first pass - figure out sections mostly */ 1158 | tokf = fopen("a.tok", "wb"); 1159 | if(tokf == NULL) 1160 | return 1; 1161 | wf = fopen("a.w", "wb"); 1162 | if(wf == NULL) 1163 | return 1; 1164 | nextdot = origin; 1165 | assemble(); 1166 | fclose(tokf); 1167 | fclose(wf); 1168 | 1169 | /* second pass - figure out addresses */ 1170 | if(error){ 1171 | fprintf(stderr, "errors\n"); 1172 | return 1; 1173 | } 1174 | pass2++; 1175 | tokf = fopen("a.tok", "rb"); 1176 | if(tokf == NULL) 1177 | return 1; 1178 | wf = fopen("a.w", "rb"); 1179 | if(wf == NULL) 1180 | return 1; 1181 | toksp = 0; 1182 | nsect = 0; 1183 | assemble(); 1184 | 1185 | /* third pass */ 1186 | fseek(tokf, 0, 0); 1187 | fseek(wf, 0, 0); 1188 | toksp = 0; 1189 | nsect = 0; 1190 | assemble(); 1191 | fclose(tokf); 1192 | fclose(wf); 1193 | 1194 | outf = fopen("a.rim", "wb"); 1195 | if(outf == NULL) 1196 | return 1; 1197 | 1198 | /* 1199 | blkstart = sects[nsect-1].start; 1200 | blksize = 0; 1201 | for(s = §s[nsect-1]; s >= sects; s--){ 1202 | printf("sect %ld: %o %o\n", s-sects, s->start, s->size); 1203 | blksize += s->size; 1204 | } 1205 | writeblock(blkstart, blksize); 1206 | dumpmem(blkstart, blkstart+blksize); 1207 | */ 1208 | for(s = §s[nsect-1]; s >= sects; s--){ 1209 | writeblock(s->start, s->size); 1210 | dumpmem(s->start, s->start+s->size); 1211 | } 1212 | if(start = findsym("START"), *start) 1213 | putw10(WORD(0254000L, (*start)->v.value), outf); 1214 | else 1215 | putw10(WORD(0254000L, origin), outf); 1216 | fclose(outf); 1217 | 1218 | dumpsymbols(); 1219 | } 1220 | -------------------------------------------------------------------------------- /as.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define SYMTABSZ 8000 8 | #define nil NULL 9 | 10 | typedef int64_t word; 11 | typedef uint64_t uword; 12 | typedef int32_t hword; 13 | 14 | #define WORD(l, r) (((l)&0777777) << 18 | ((r)&0777777)) 15 | #define LW(w) (((w) >> 18)&0777777) 16 | #define RW(w) ((w)&0777777) 17 | 18 | enum Valtype 19 | { 20 | Undef = 0, 21 | Abs, 22 | Op, 23 | Io, 24 | Asm, 25 | }; 26 | 27 | enum Toktype 28 | { 29 | Unused = 0, 30 | Eof, 31 | Symbol, 32 | Word, 33 | Newline, 34 | Space, 35 | Not, 36 | DQuote, 37 | Mod, 38 | And, 39 | LParen, 40 | RParen, 41 | Times, 42 | Plus, 43 | Comma, 44 | Cons, 45 | Minus, 46 | Period, 47 | Div, 48 | Colon, 49 | Semi, 50 | Less, 51 | Equal, 52 | Great, 53 | At, 54 | LBrack, 55 | RBrack, 56 | LBrace, 57 | Or, 58 | RBrace, 59 | 60 | /* only used as character classes */ 61 | Digit, 62 | Letter, 63 | }; 64 | 65 | typedef struct Value Value; 66 | struct Value 67 | { 68 | int type; 69 | word value; 70 | }; 71 | 72 | typedef struct Sym Sym; 73 | struct Sym 74 | { 75 | char name[24]; 76 | Value v; 77 | }; 78 | 79 | typedef struct Token Token; 80 | struct Token 81 | { 82 | int type; 83 | union { 84 | word w; 85 | Sym *s; 86 | }; 87 | }; 88 | 89 | typedef struct Section Section; 90 | struct Section 91 | { 92 | hword start; 93 | hword size; 94 | }; 95 | 96 | int chartab[] = { 97 | Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, 98 | Unused, Unused, Newline, Unused, Unused, Unused, Unused, Unused, 99 | Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, 100 | Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, 101 | Space, Not, DQuote, Unused, Unused, Mod, And, Unused, 102 | LParen, RParen, Times, Plus, Comma, Minus, Period, Div, 103 | Digit, Digit, Digit, Digit, Digit, Digit, Digit, Digit, 104 | Digit, Digit, Colon, Semi, Less, Equal, Great, Unused, 105 | At, Letter, Letter, Letter, Letter, Letter, Letter, Letter, 106 | Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, 107 | Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, 108 | Letter, Letter, Letter, LBrack, Unused, RBrack, Unused, Letter, 109 | Unused, Letter, Letter, Letter, Letter, Letter, Letter, Letter, 110 | Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, 111 | Letter, Letter, Letter, Letter, Letter, Letter, Letter, Letter, 112 | Letter, Letter, Letter, LBrace, Or, RBrace, Unused, Unused 113 | }; 114 | #define CTYPE(c) chartab[(c)&0177] 115 | 116 | Sym *symtab[SYMTABSZ]; 117 | Sym syms[] = { 118 | { ".", Abs, 0 }, 119 | { "ASCII", Asm, 0 }, 120 | 121 | { "DFAD", Op, 0110 }, 122 | { "DFSB", Op, 0111 }, 123 | { "DFMP", Op, 0112 }, 124 | { "DFDV", Op, 0113 }, 125 | { "DMOVE", Op, 0120 }, 126 | { "DMOVN", Op, 0121 }, 127 | { "FIX", Op, 0122 }, 128 | { "XBLT", Op, 0123 }, 129 | { "DMOVEM",Op, 0124 }, 130 | { "DMOVNM",Op, 0125 }, 131 | { "FIXR", Op, 0126 }, 132 | { "FLTR", Op, 0127 }, 133 | { "UFA", Op, 0130 }, 134 | { "DFN", Op, 0131 }, 135 | { "FSC", Op, 0132 }, 136 | 137 | { "IBP", Op, 0133 }, 138 | { "ILDB", Op, 0134 }, 139 | { "LDB", Op, 0135 }, 140 | { "IDPB", Op, 0136 }, 141 | { "DPB", Op, 0137 }, 142 | 143 | { "FAD", Op, 0140 }, 144 | { "FADL", Op, 0141 }, 145 | { "FADM", Op, 0142 }, 146 | { "FADB", Op, 0143 }, 147 | { "FADR", Op, 0144 }, 148 | { "FADRI", Op, 0145 }, 149 | { "FADRM", Op, 0146 }, 150 | { "FADRB", Op, 0147 }, 151 | { "FSB", Op, 0150 }, 152 | { "FSBL", Op, 0151 }, 153 | { "FSBM", Op, 0152 }, 154 | { "FSBB", Op, 0153 }, 155 | { "FSBR", Op, 0154 }, 156 | { "FSBRI", Op, 0155 }, 157 | { "FSBRM", Op, 0156 }, 158 | { "FSBRB", Op, 0157 }, 159 | { "FMP", Op, 0160 }, 160 | { "FMPL", Op, 0161 }, 161 | { "FMPM", Op, 0162 }, 162 | { "FMPB", Op, 0163 }, 163 | { "FMPR", Op, 0164 }, 164 | { "FMPRI", Op, 0165 }, 165 | { "FMPRM", Op, 0166 }, 166 | { "FMPRB", Op, 0167 }, 167 | { "FDV", Op, 0170 }, 168 | { "FDVL", Op, 0171 }, 169 | { "FDVM", Op, 0172 }, 170 | { "FDVB", Op, 0173 }, 171 | { "FDVR", Op, 0174 }, 172 | { "FDVRI", Op, 0175 }, 173 | { "FDVRM", Op, 0176 }, 174 | { "FDVRB", Op, 0177 }, 175 | 176 | { "MOVE", Op, 0200 }, 177 | { "MOVEI", Op, 0201 }, 178 | { "MOVEM", Op, 0202 }, 179 | { "MOVES", Op, 0203 }, 180 | { "MOVS", Op, 0204 }, 181 | { "MOVSI", Op, 0205 }, 182 | { "MOVSM", Op, 0206 }, 183 | { "MOVSS", Op, 0207 }, 184 | { "MOVN", Op, 0210 }, 185 | { "MOVNI", Op, 0211 }, 186 | { "MOVNM", Op, 0212 }, 187 | { "MOVNS", Op, 0213 }, 188 | { "MOVM", Op, 0214 }, 189 | { "MOVMI", Op, 0215 }, 190 | { "MOVMM", Op, 0216 }, 191 | { "MOVMS", Op, 0217 }, 192 | 193 | { "IMUL", Op, 0220 }, 194 | { "IMULI", Op, 0221 }, 195 | { "IMULM", Op, 0222 }, 196 | { "IMULB", Op, 0223 }, 197 | { "MUL", Op, 0224 }, 198 | { "MULI", Op, 0225 }, 199 | { "MULM", Op, 0226 }, 200 | { "MULB", Op, 0227 }, 201 | { "IDIV", Op, 0230 }, 202 | { "IDIVI", Op, 0231 }, 203 | { "IDIVM", Op, 0232 }, 204 | { "IDIVB", Op, 0233 }, 205 | { "DIV", Op, 0234 }, 206 | { "DIVI", Op, 0235 }, 207 | { "DIVM", Op, 0236 }, 208 | { "DIVB", Op, 0237 }, 209 | 210 | { "ASH", Op, 0240 }, 211 | { "ROT", Op, 0241 }, 212 | { "LSH", Op, 0242 }, 213 | { "JFFO", Op, 0243 }, 214 | { "ASHC", Op, 0244 }, 215 | { "ROTC", Op, 0245 }, 216 | { "LSHC", Op, 0246 }, 217 | 218 | { "EXCH", Op, 0250 }, 219 | { "BLT", Op, 0251 }, 220 | { "AOBJP", Op, 0252 }, 221 | { "AOBJN", Op, 0253 }, 222 | 223 | { "JRST", Op, 0254 }, 224 | { "JFCL", Op, 0255 }, 225 | { "XCT", Op, 0256 }, 226 | { "MAP", Op, 0257 }, 227 | { "PUSHJ", Op, 0260 }, 228 | { "PUSH", Op, 0261 }, 229 | { "POP", Op, 0262 }, 230 | { "POPJ", Op, 0263 }, 231 | { "JSR", Op, 0264 }, 232 | { "JSP", Op, 0265 }, 233 | { "JSA", Op, 0266 }, 234 | { "JRA", Op, 0267 }, 235 | 236 | { "ADD", Op, 0270 }, 237 | { "ADDI", Op, 0271 }, 238 | { "ADDM", Op, 0272 }, 239 | { "ADDB", Op, 0273 }, 240 | { "SUB", Op, 0274 }, 241 | { "SUBI", Op, 0275 }, 242 | { "SUBM", Op, 0276 }, 243 | { "SUBB", Op, 0277 }, 244 | 245 | { "CAI", Op, 0300 }, 246 | { "CAIL", Op, 0301 }, 247 | { "CAIE", Op, 0302 }, 248 | { "CAILE", Op, 0303 }, 249 | { "CAIA", Op, 0304 }, 250 | { "CAIGE", Op, 0305 }, 251 | { "CAIN", Op, 0306 }, 252 | { "CAIG", Op, 0307 }, 253 | { "CAM", Op, 0310 }, 254 | { "CAML", Op, 0311 }, 255 | { "CAME", Op, 0312 }, 256 | { "CAMLE", Op, 0313 }, 257 | { "CAMA", Op, 0314 }, 258 | { "CAMGE", Op, 0315 }, 259 | { "CAMN", Op, 0316 }, 260 | { "CAMG", Op, 0317 }, 261 | { "JUMP", Op, 0320 }, 262 | { "JUMPL", Op, 0321 }, 263 | { "JUMPE", Op, 0322 }, 264 | { "JUMPLE",Op, 0323 }, 265 | { "JUMPA", Op, 0324 }, 266 | { "JUMPGE",Op, 0325 }, 267 | { "JUMPN", Op, 0326 }, 268 | { "JUMPG", Op, 0327 }, 269 | { "SKIP", Op, 0330 }, 270 | { "SKIPL", Op, 0331 }, 271 | { "SKIPE", Op, 0332 }, 272 | { "SKIPLE",Op, 0333 }, 273 | { "SKIPA", Op, 0334 }, 274 | { "SKIPGE",Op, 0335 }, 275 | { "SKIPN", Op, 0336 }, 276 | { "SKIPG", Op, 0337 }, 277 | { "AOJ", Op, 0340 }, 278 | { "AOJL", Op, 0341 }, 279 | { "AOJE", Op, 0342 }, 280 | { "AOJLE", Op, 0343 }, 281 | { "AOJA", Op, 0344 }, 282 | { "AOJGE", Op, 0345 }, 283 | { "AOJN", Op, 0346 }, 284 | { "AOJG", Op, 0347 }, 285 | { "AOS", Op, 0350 }, 286 | { "AOSL", Op, 0351 }, 287 | { "AOSE", Op, 0352 }, 288 | { "AOSLE", Op, 0353 }, 289 | { "AOSA", Op, 0354 }, 290 | { "AOSGE", Op, 0355 }, 291 | { "AOSN", Op, 0356 }, 292 | { "AOSG", Op, 0357 }, 293 | { "SOJ", Op, 0360 }, 294 | { "SOJL", Op, 0361 }, 295 | { "SOJE", Op, 0362 }, 296 | { "SOJLE", Op, 0363 }, 297 | { "SOJA", Op, 0364 }, 298 | { "SOJGE", Op, 0365 }, 299 | { "SOJN", Op, 0366 }, 300 | { "SOJG", Op, 0367 }, 301 | { "SOS", Op, 0370 }, 302 | { "SOSL", Op, 0371 }, 303 | { "SOSE", Op, 0372 }, 304 | { "SOSLE", Op, 0373 }, 305 | { "SOSA", Op, 0374 }, 306 | { "SOSGE", Op, 0375 }, 307 | { "SOSN", Op, 0376 }, 308 | { "SOSG", Op, 0377 }, 309 | 310 | { "SETZ", Op, 0400 }, 311 | { "SETZI", Op, 0401 }, 312 | { "SETZM", Op, 0402 }, 313 | { "SETZB", Op, 0403 }, 314 | { "AND", Op, 0404 }, 315 | { "ANDI", Op, 0405 }, 316 | { "ANDM", Op, 0406 }, 317 | { "ANDB", Op, 0407 }, 318 | { "ANDCA", Op, 0410 }, 319 | { "ANDCAI",Op, 0411 }, 320 | { "ANDCAM",Op, 0412 }, 321 | { "ANDCAB",Op, 0413 }, 322 | { "SETM", Op, 0414 }, 323 | { "SETMI", Op, 0415 }, 324 | { "XMOVEI",Op, 0415 }, 325 | { "SETMM", Op, 0416 }, 326 | { "SETMB", Op, 0417 }, 327 | { "ANDCM", Op, 0420 }, 328 | { "ANDCMI",Op, 0421 }, 329 | { "ANDCMM",Op, 0422 }, 330 | { "ANDCMB",Op, 0423 }, 331 | { "SETA", Op, 0424 }, 332 | { "SETAI", Op, 0425 }, 333 | { "SETAM", Op, 0426 }, 334 | { "SETAB", Op, 0427 }, 335 | { "XOR", Op, 0430 }, 336 | { "XORI", Op, 0431 }, 337 | { "XORM", Op, 0432 }, 338 | { "XORB", Op, 0433 }, 339 | { "IOR", Op, 0434 }, 340 | { "IORI", Op, 0435 }, 341 | { "IORM", Op, 0436 }, 342 | { "IORB", Op, 0437 }, 343 | { "ANDCB", Op, 0440 }, 344 | { "ANDCBI",Op, 0441 }, 345 | { "ANDCBM",Op, 0442 }, 346 | { "ANDCBB",Op, 0443 }, 347 | { "EQV", Op, 0444 }, 348 | { "EQVI", Op, 0445 }, 349 | { "EQVM", Op, 0446 }, 350 | { "EQVB", Op, 0447 }, 351 | { "SETCA", Op, 0450 }, 352 | { "SETCAI",Op, 0451 }, 353 | { "SETCAM",Op, 0452 }, 354 | { "SETCAB",Op, 0453 }, 355 | { "ORCA", Op, 0454 }, 356 | { "ORCAI", Op, 0455 }, 357 | { "ORCAM", Op, 0456 }, 358 | { "ORCAB", Op, 0457 }, 359 | { "SETCM", Op, 0460 }, 360 | { "SETCMI",Op, 0461 }, 361 | { "SETCMM",Op, 0462 }, 362 | { "SETCMB",Op, 0463 }, 363 | { "ORCM", Op, 0464 }, 364 | { "ORCMI", Op, 0465 }, 365 | { "ORCMM", Op, 0466 }, 366 | { "ORCMB", Op, 0467 }, 367 | { "ORCB", Op, 0470 }, 368 | { "ORCBI", Op, 0471 }, 369 | { "ORCBM", Op, 0472 }, 370 | { "ORCBB", Op, 0473 }, 371 | { "SETO", Op, 0474 }, 372 | { "SETOI", Op, 0475 }, 373 | { "SETOM", Op, 0476 }, 374 | { "SETOB", Op, 0477 }, 375 | 376 | { "HLL", Op, 0500 }, 377 | { "HLLI", Op, 0501 }, 378 | { "HLLM", Op, 0502 }, 379 | { "HLLS", Op, 0503 }, 380 | { "HRL", Op, 0504 }, 381 | { "HRLI", Op, 0505 }, 382 | { "HRLM", Op, 0506 }, 383 | { "HRLS", Op, 0507 }, 384 | { "HLLZ", Op, 0510 }, 385 | { "HLLZI", Op, 0511 }, 386 | { "HLLZM", Op, 0512 }, 387 | { "HLLZS", Op, 0513 }, 388 | { "HRLZ", Op, 0514 }, 389 | { "HRLZI", Op, 0515 }, 390 | { "HRLZM", Op, 0516 }, 391 | { "HRLZS", Op, 0517 }, 392 | { "HLLO", Op, 0520 }, 393 | { "HLLOI", Op, 0521 }, 394 | { "HLLOM", Op, 0522 }, 395 | { "HLLOS", Op, 0523 }, 396 | { "HRLO", Op, 0524 }, 397 | { "HRLOI", Op, 0525 }, 398 | { "HRLOM", Op, 0526 }, 399 | { "HRLOS", Op, 0527 }, 400 | { "HLLE", Op, 0530 }, 401 | { "HLLEI", Op, 0531 }, 402 | { "HLLEM", Op, 0532 }, 403 | { "HLLES", Op, 0533 }, 404 | { "HRLE", Op, 0534 }, 405 | { "HRLEI", Op, 0535 }, 406 | { "HRLEM", Op, 0536 }, 407 | { "HRLES", Op, 0537 }, 408 | { "HRR", Op, 0540 }, 409 | { "HRRI", Op, 0541 }, 410 | { "HRRM", Op, 0542 }, 411 | { "HRRS", Op, 0543 }, 412 | { "HLR", Op, 0544 }, 413 | { "HLRI", Op, 0545 }, 414 | { "HLRM", Op, 0546 }, 415 | { "HLRS", Op, 0547 }, 416 | { "HRRZ", Op, 0550 }, 417 | { "HRRZI", Op, 0551 }, 418 | { "HRRZM", Op, 0552 }, 419 | { "HRRZS", Op, 0553 }, 420 | { "HLRZ", Op, 0554 }, 421 | { "HLRZI", Op, 0555 }, 422 | { "HLRZM", Op, 0556 }, 423 | { "HLRZS", Op, 0557 }, 424 | { "HRRO", Op, 0560 }, 425 | { "HRROI", Op, 0561 }, 426 | { "HRROM", Op, 0562 }, 427 | { "HRROS", Op, 0563 }, 428 | { "HLRO", Op, 0564 }, 429 | { "HLROI", Op, 0565 }, 430 | { "HLROM", Op, 0566 }, 431 | { "HLROS", Op, 0567 }, 432 | { "HRRE", Op, 0570 }, 433 | { "HRREI", Op, 0571 }, 434 | { "HRREM", Op, 0572 }, 435 | { "HRRES", Op, 0573 }, 436 | { "HLRE", Op, 0574 }, 437 | { "HLREI", Op, 0575 }, 438 | { "HLREM", Op, 0576 }, 439 | { "HLRES", Op, 0577 }, 440 | 441 | { "TRN", Op, 0600 }, 442 | { "TLN", Op, 0601 }, 443 | { "TRNE", Op, 0602 }, 444 | { "TLNE", Op, 0603 }, 445 | { "TRNA", Op, 0604 }, 446 | { "TLNA", Op, 0605 }, 447 | { "TRNN", Op, 0606 }, 448 | { "TLNN", Op, 0607 }, 449 | { "TDN", Op, 0610 }, 450 | { "TSN", Op, 0611 }, 451 | { "TDNE", Op, 0612 }, 452 | { "TSNE", Op, 0613 }, 453 | { "TDNA", Op, 0614 }, 454 | { "TSNA", Op, 0615 }, 455 | { "TDNN", Op, 0616 }, 456 | { "TSNN", Op, 0617 }, 457 | { "TRZ", Op, 0620 }, 458 | { "TLZ", Op, 0621 }, 459 | { "TRZE", Op, 0622 }, 460 | { "TLZE", Op, 0623 }, 461 | { "TRZA", Op, 0624 }, 462 | { "TLZA", Op, 0625 }, 463 | { "TRZN", Op, 0626 }, 464 | { "TLZN", Op, 0627 }, 465 | { "TDZ", Op, 0630 }, 466 | { "TSZ", Op, 0631 }, 467 | { "TDZE", Op, 0632 }, 468 | { "TSZE", Op, 0633 }, 469 | { "TDZA", Op, 0634 }, 470 | { "TSZA", Op, 0635 }, 471 | { "TDZN", Op, 0636 }, 472 | { "TSZN", Op, 0637 }, 473 | { "TRC", Op, 0640 }, 474 | { "TLC", Op, 0641 }, 475 | { "TRCE", Op, 0642 }, 476 | { "TLCE", Op, 0643 }, 477 | { "TRCA", Op, 0644 }, 478 | { "TLCA", Op, 0645 }, 479 | { "TRCN", Op, 0646 }, 480 | { "TLCN", Op, 0647 }, 481 | { "TDC", Op, 0650 }, 482 | { "TSC", Op, 0651 }, 483 | { "TDCE", Op, 0652 }, 484 | { "TSCE", Op, 0653 }, 485 | { "TDCA", Op, 0654 }, 486 | { "TSCA", Op, 0655 }, 487 | { "TDCN", Op, 0656 }, 488 | { "TSCN", Op, 0657 }, 489 | { "TRO", Op, 0660 }, 490 | { "TLO", Op, 0661 }, 491 | { "TROE", Op, 0662 }, 492 | { "TLOE", Op, 0663 }, 493 | { "TROA", Op, 0664 }, 494 | { "TLOA", Op, 0665 }, 495 | { "TRON", Op, 0666 }, 496 | { "TLON", Op, 0667 }, 497 | { "TDO", Op, 0670 }, 498 | { "TSO", Op, 0671 }, 499 | { "TDOE", Op, 0672 }, 500 | { "TSOE", Op, 0673 }, 501 | { "TDOA", Op, 0674 }, 502 | { "TSOA", Op, 0675 }, 503 | { "TDON", Op, 0676 }, 504 | { "TSON", Op, 0677 }, 505 | 506 | { "BLKI", Io, 070000 }, 507 | { "BLKO", Io, 070010 }, 508 | { "DATAI", Io, 070004 }, 509 | { "DATAO", Io, 070014 }, 510 | { "CONO", Io, 070020 }, 511 | { "CONI", Io, 070024 }, 512 | { "CONSZ", Io, 070030 }, 513 | { "CONSO", Io, 070034 }, 514 | { "", 0, 0 } 515 | }; 516 | 517 | hword assemble(void); 518 | 519 | int pass2; 520 | int error; 521 | word origin; 522 | word mem[01000000]; 523 | 524 | #define MAXSECT 100 /* increase if necessary */ 525 | Section sects[MAXSECT]; 526 | int nsect; 527 | hword nextdot; 528 | 529 | FILE *tokf; 530 | FILE *wf; 531 | FILE *outf; 532 | 533 | int nextc; 534 | int toksp; 535 | Token tokstk[2]; 536 | Sym *dot; 537 | 538 | #define PUSHT(t) tokstk[toksp++] = (t) 539 | 540 | void 541 | putw10(word w, FILE *f) 542 | { 543 | int i; 544 | w &= 0777777777777; 545 | for(i = 5; i >= 0; i--) 546 | putc(((w>>i*6)&077)|0200, f); 547 | } 548 | 549 | void 550 | writeblock(word origin, word count) 551 | { 552 | int i; 553 | word chksm; 554 | word w; 555 | 556 | chksm = 0; 557 | putw10(w = WORD(-count, origin-1), outf); 558 | chksm += w; 559 | for(i = 0; i < count; i++){ 560 | chksm += mem[i+origin]; 561 | putw10(mem[i+origin], outf); 562 | } 563 | putw10(-chksm, outf); 564 | } 565 | 566 | int 567 | ch(void) 568 | { 569 | int c; 570 | if(nextc){ 571 | c = nextc; 572 | nextc = 0; 573 | return c; 574 | } 575 | c = getchar(); 576 | tail: 577 | if(c == '#'){ 578 | while(c = getchar(), c != '\n') 579 | if(c == EOF) return c; 580 | goto tail; 581 | } 582 | if(c == '\t' || c == '\r') 583 | c = ' '; 584 | return c; 585 | } 586 | 587 | int 588 | chsp(void) 589 | { 590 | int c; 591 | while(c = ch(), c == ' '); 592 | return c; 593 | } 594 | 595 | int 596 | hash(char *s) 597 | { 598 | int hsh; 599 | hsh = 0; 600 | for(; *s != '\0'; s++) 601 | hsh += *s; 602 | return hsh % SYMTABSZ; 603 | } 604 | 605 | Sym** 606 | findsym(char *name) 607 | { 608 | int hsh; 609 | char *p; 610 | Sym **s; 611 | 612 | hsh = hash(name); 613 | s = &symtab[hsh]; 614 | for(;;){ 615 | if(*s == nil || 616 | strncmp((*s)->name, name, 24) == 0) 617 | return s; 618 | s++; 619 | if(s == &symtab[SYMTABSZ]) 620 | s = symtab; 621 | if(s == &symtab[hsh]){ 622 | fprintf(stderr, "symbol table full\n"); 623 | exit(1); 624 | } 625 | } 626 | } 627 | 628 | Sym* 629 | getsym(char *name) 630 | { 631 | Sym **p; 632 | p = findsym(name); 633 | if(*p) 634 | return *p; 635 | *p = malloc(sizeof(Sym)); 636 | strncpy((*p)->name, name, 24); 637 | (*p)->v.type = Undef; 638 | (*p)->v.value = 0; 639 | return *p; 640 | } 641 | 642 | word 643 | number(void) 644 | { 645 | int c; 646 | word n, oct, dec; 647 | int sign; 648 | 649 | sign = 1; 650 | if(c = ch(), c == '-') 651 | sign = -1; 652 | else 653 | nextc = c; 654 | oct = dec = 0; 655 | while(c = ch(), CTYPE(c) == Digit){ 656 | oct = (oct << 3) | (c-'0'); 657 | dec = dec*10 + (c-'0'); 658 | } 659 | if(c == '.') 660 | n = dec; 661 | else{ 662 | n = oct; 663 | nextc = c; 664 | } 665 | return (n*sign)&0777777777777; 666 | } 667 | 668 | int 669 | strchar(int delim) 670 | { 671 | int c; 672 | c = getchar(); 673 | if(delim && c == delim) 674 | return 0400; 675 | if(c != '\\') 676 | return c; 677 | c = getchar(); 678 | switch(c){ 679 | case 'b': 680 | c = '\b'; 681 | break; 682 | 683 | case 'n': 684 | c = '\n'; 685 | break; 686 | 687 | case 'r': 688 | c = '\r'; 689 | break; 690 | 691 | case '\\': 692 | c = '\\'; 693 | break; 694 | 695 | case '0': 696 | c = 0; 697 | break; 698 | } 699 | return c; 700 | } 701 | 702 | Token 703 | token(void) 704 | { 705 | char name[24]; 706 | char *p; 707 | int c; 708 | Token t; 709 | 710 | if(toksp){ 711 | t = tokstk[--toksp]; 712 | return t; 713 | } 714 | if(pass2){ 715 | fread(&t, sizeof(t), 1, tokf); 716 | return t; 717 | } 718 | c = chsp(); 719 | if(c == EOF) 720 | t.type = Eof; 721 | else 722 | switch(CTYPE(c)){ 723 | case Period: 724 | case Letter: 725 | p = name; 726 | do{ 727 | if(p < name+23) 728 | *p++ = toupper(c); 729 | }while(c = ch(), CTYPE(c) == Letter || 730 | CTYPE(c) == Period || 731 | CTYPE(c) == Digit); 732 | nextc = c; 733 | *p++ = '\0'; 734 | t.type = Symbol; 735 | t.s = getsym(name); 736 | break; 737 | 738 | case Digit: 739 | nextc = c; 740 | t.type = Word; 741 | t.w = number(); 742 | break; 743 | 744 | case DQuote: 745 | t.type = Word; 746 | t.w = strchar(0); 747 | break; 748 | 749 | case Comma: 750 | c = chsp(); 751 | if(CTYPE(c) == Comma) 752 | t.type = Cons; 753 | else{ 754 | t.type = Comma; 755 | nextc = c; 756 | } 757 | break; 758 | 759 | case Unused: 760 | fprintf(stderr, "unknown char: %c\n", c); 761 | break; 762 | 763 | default: 764 | t.type = CTYPE(c); 765 | break; 766 | } 767 | fwrite(&t, sizeof(t), 1, tokf); 768 | return t; 769 | } 770 | 771 | void 772 | directive(int type) 773 | { 774 | uword w; 775 | int c, i, s; 776 | 777 | if(type == 0){ /* ascii */ 778 | /* save ascii words in word file because they're not tokens */ 779 | if(!pass2){ 780 | c = chsp(); 781 | if(c != '"'){ 782 | fprintf(stderr, "\" expected\n"); 783 | return; 784 | } 785 | w = 0; 786 | i = 0; 787 | s = 29; 788 | while(c = strchar('"'), c != 0400 && c != EOF){ 789 | c &= 0177; 790 | w = w | ((uword)c << s); 791 | s -= 7; 792 | if(++i == 5){ 793 | fwrite(&w, sizeof(w), 1, wf); 794 | dot->v.value++; 795 | i = 0; 796 | s = 29; 797 | w = 0; 798 | } 799 | } 800 | if(i){ 801 | fwrite(&w, sizeof(w), 1, wf); 802 | dot->v.value++; 803 | } 804 | w = ~0; 805 | fwrite(&w, sizeof(w), 1, wf); 806 | dot->v.value++; 807 | }else{ 808 | while(fread(&w, sizeof(w), 1, wf), w != ~0) 809 | mem[dot->v.value++] = w; 810 | } 811 | } 812 | } 813 | 814 | Value 815 | apply(int op, Value v1, Value v2) 816 | { 817 | switch(op){ 818 | case Not: 819 | v1.value |= ~v2.value; 820 | break; 821 | 822 | case Plus: 823 | v1.value += v2.value; 824 | break; 825 | 826 | case Minus: 827 | v1.value -= v2.value; 828 | break; 829 | 830 | case Times: 831 | v1.value *= v2.value; 832 | break; 833 | 834 | case Div: 835 | v1.value /= v2.value; 836 | break; 837 | 838 | case Mod: 839 | v1.value %= v2.value; 840 | break; 841 | 842 | case And: 843 | v1.value &= v2.value; 844 | break; 845 | 846 | case Or: 847 | v1.value |= v2.value; 848 | break; 849 | 850 | case Less: 851 | v1.value <<= v2.value; 852 | break; 853 | 854 | case Great: 855 | v1.value >>= v2.value; 856 | break; 857 | 858 | case Cons: 859 | v1.value = WORD(v1.value, v2.value); 860 | break; 861 | 862 | default: 863 | fprintf(stderr, "unknown op %d\n", op); 864 | return v2; 865 | } 866 | v1.value &= 0777777777777; 867 | return v1; 868 | } 869 | 870 | Value 871 | expr(void) 872 | { 873 | Token t; 874 | int op; 875 | Value v, v2; 876 | hword savedot; 877 | 878 | v.type = Abs; 879 | v.value = 0; 880 | op = Plus; 881 | 882 | /* TODO: just accept possible tokens */ 883 | while(t = token(), 884 | t.type != RBrack && t.type != RBrace && t.type != Comma && 885 | t.type != LParen && t.type != RParen && 886 | t.type != Newline && t.type != Semi){ 887 | switch(t.type){ 888 | case Word: 889 | v2.type = Abs; 890 | v2.value = t.w; 891 | v = apply(op, v, v2); 892 | op = Plus; 893 | break; 894 | 895 | case Symbol: 896 | v = apply(op, v, t.s->v); 897 | op = Plus; 898 | break; 899 | 900 | case LBrack: 901 | v2 = expr(); 902 | t = token(); 903 | if(t.type != RBrack){ 904 | fprintf(stderr, "']' expected\n"); 905 | error = 1; 906 | PUSHT(t); 907 | } 908 | v = apply(op, v, v2); 909 | op = Plus; 910 | break; 911 | 912 | case LBrace: 913 | v2.type = Abs; 914 | savedot = dot->v.value; 915 | v2.value = assemble(); 916 | dot->v.value = savedot; 917 | t = token(); 918 | if(t.type != RBrace){ 919 | fprintf(stderr, "'}' expected\n"); 920 | error = 1; 921 | PUSHT(t); 922 | } 923 | v = apply(op, v, v2); 924 | op = Plus; 925 | break; 926 | 927 | case Not: 928 | case Plus: 929 | case Minus: 930 | case Times: 931 | case Div: 932 | case Mod: 933 | case And: 934 | case Or: 935 | case Less: 936 | case Great: 937 | case Cons: 938 | op = t.type; 939 | break; 940 | 941 | default: 942 | fprintf(stderr, "can't parse expr %d\n", t.type); 943 | error = 1; 944 | v.type = Abs; 945 | v.value = 0; 946 | } 947 | } 948 | PUSHT(t); 949 | return v; 950 | } 951 | 952 | word 953 | opline(void) 954 | { 955 | word inst; 956 | word op, ac, i, x, y; 957 | word w; 958 | Token t; 959 | Value v; 960 | int type; 961 | 962 | type = 0; 963 | ac = i = x = y = 0; 964 | t = token(); 965 | if(t.s->v.type == Op){ 966 | op = t.s->v.value & 0777; 967 | }else if(t.s->v.type == Io){ 968 | type = 1; 969 | op = t.s->v.value & 077774; 970 | }else{ 971 | fprintf(stderr, "expected opcode\n"); 972 | error = 1; 973 | } 974 | 975 | /* So many gotos, sorry Edsger */ 976 | t = token(); 977 | if(t.type == At){ 978 | i = 1; 979 | t = token(); 980 | goto Y; 981 | } 982 | if(t.type == LParen) 983 | goto X; 984 | if(t.type == Newline || t.type == Semi){ 985 | PUSHT(t); 986 | goto end; 987 | } 988 | PUSHT(t); /* has to be AC or Y now */ 989 | w = expr().value; 990 | t = token(); 991 | if(t.type == Comma) 992 | ac = w & (type == 0 ? 017 : 0774); 993 | else{ 994 | y = w & 0777777; 995 | if(t.type == LParen) 996 | goto X; 997 | PUSHT(t); 998 | goto end; 999 | } 1000 | t = token(); 1001 | if(t.type == Newline || t.type == Semi){ 1002 | PUSHT(t); 1003 | goto end; 1004 | } 1005 | if(t.type == At){ 1006 | i = 1; 1007 | t = token(); 1008 | } 1009 | Y: 1010 | if(t.type != LParen){ 1011 | PUSHT(t); 1012 | y = expr().value & 0777777; 1013 | t = token(); 1014 | if(t.type == LParen) 1015 | goto X; 1016 | PUSHT(t); 1017 | }else{ 1018 | X: 1019 | x = expr().value & 017; 1020 | t = token(); 1021 | if(t.type != RParen){ 1022 | fprintf(stderr, ") expected\n"); 1023 | error = 1; 1024 | PUSHT(t); 1025 | } 1026 | } 1027 | 1028 | end: 1029 | if(type == 0) 1030 | inst = op << 27 | 1031 | ac << 23 | 1032 | i << 22 | 1033 | x << 18 | 1034 | y; 1035 | else 1036 | inst = op << 21 | 1037 | ac << 24 | /* this is correct */ 1038 | i << 22 | 1039 | x << 18 | 1040 | y; 1041 | // printf("inst: %lo\n", inst); 1042 | return inst; 1043 | } 1044 | 1045 | hword 1046 | assemble(void) 1047 | { 1048 | Token t, tt; 1049 | Section *sect; 1050 | sect = §s[nsect++]; 1051 | if(sect == §s[MAXSECT]){ 1052 | fprintf(stderr, "ran out of sections\n"); 1053 | exit(1); 1054 | } 1055 | dot->v.value = sect->start; 1056 | // printf("section %d %o %o\n", nsect, sect->start, sect->size); 1057 | 1058 | while(t = token(), t.type != Eof && t.type != RBrace){ 1059 | switch(t.type){ 1060 | case Symbol: 1061 | if(t.s->v.type == Asm){ 1062 | directive(t.s->v.value); 1063 | t = token(); 1064 | break; 1065 | } 1066 | if(t.s->v.type == Op || 1067 | t.s->v.type == Io){ 1068 | PUSHT(t); 1069 | mem[dot->v.value] = opline(); 1070 | dot->v.value++; 1071 | t = token(); 1072 | break; 1073 | } 1074 | tt = token(); 1075 | if(tt.type == Colon){ 1076 | // if(t.s->v.type != Undef && 1077 | // t.s->v.value != dot->v.value) 1078 | // fprintf(stderr, "redefining %s\n", 1079 | // t.s->name); 1080 | t.s->v = dot->v; 1081 | continue; 1082 | }else if(tt.type == Equal){ 1083 | t.s->v = expr(); 1084 | t = token(); 1085 | }else{ 1086 | PUSHT(tt); 1087 | goto exp; 1088 | } 1089 | break; 1090 | 1091 | exp: 1092 | case Not: 1093 | case LBrace: 1094 | case LBrack: 1095 | case Minus: 1096 | case Word: 1097 | PUSHT(t); 1098 | mem[dot->v.value++] = expr().value; 1099 | t = token(); 1100 | break; 1101 | 1102 | default: 1103 | if(t.type != Newline && t.type != Semi){ 1104 | fprintf(stderr, "can't parse %d\n", t.type); 1105 | error = 1; 1106 | } 1107 | } 1108 | 1109 | // if(!pass2) 1110 | // printf("statement %d\n", t.type); 1111 | if(t.type == RBrace) 1112 | break; 1113 | if(t.type != Newline && t.type != Semi){ 1114 | PUSHT(t); 1115 | fprintf(stderr, "statement not ended %d\n", t.type); 1116 | error = 1; 1117 | while(t.type != Newline && t.type != Semi) 1118 | t = token(); 1119 | } 1120 | } 1121 | PUSHT(t); 1122 | 1123 | if(!pass2){ 1124 | sect->size = dot->v.value - sect->start; 1125 | sect->start = nextdot; 1126 | nextdot += sect->size; 1127 | // printf("size: %o %o\n", sect->size, sect->start); 1128 | } 1129 | return sect->start; 1130 | } 1131 | 1132 | void 1133 | dumpsymbols(void) 1134 | { 1135 | int i; 1136 | for(i = 0; i < SYMTABSZ; i++) 1137 | if(symtab[i] && symtab[i]->v.type != Op && 1138 | symtab[i]->v.type != Io) 1139 | fprintf(stderr, "%s %o %lo\n", symtab[i]->name, 1140 | symtab[i]->v.type, symtab[i]->v.value); 1141 | } 1142 | 1143 | void 1144 | dumpmem(word start, word end) 1145 | { 1146 | for(; start < end; start++) 1147 | printf("%lo: %lo\n", start, mem[start]); 1148 | } 1149 | 1150 | void 1151 | initsyms(void) 1152 | { 1153 | int hsh; 1154 | Sym *s, **sp; 1155 | 1156 | for(s = syms; s->name[0]; s++){ 1157 | sp = findsym(s->name); 1158 | *sp = s; 1159 | } 1160 | dot = getsym("."); 1161 | } 1162 | 1163 | int 1164 | main(int argc, char *argv[]) 1165 | { 1166 | Section *s; 1167 | Sym **start; 1168 | hword blkstart, blksize; 1169 | 1170 | origin = 01000; 1171 | initsyms(); 1172 | 1173 | /* first pass - figure out sections mostly */ 1174 | tokf = fopen("a.tok", "wb"); 1175 | if(tokf == NULL) 1176 | return 1; 1177 | wf = fopen("a.w", "wb"); 1178 | if(wf == NULL) 1179 | return 1; 1180 | nextdot = origin; 1181 | assemble(); 1182 | fclose(tokf); 1183 | fclose(wf); 1184 | 1185 | /* second pass - figure out addresses */ 1186 | if(error){ 1187 | fprintf(stderr, "errors\n"); 1188 | return 1; 1189 | } 1190 | pass2++; 1191 | tokf = fopen("a.tok", "rb"); 1192 | if(tokf == NULL) 1193 | return 1; 1194 | wf = fopen("a.w", "rb"); 1195 | if(wf == NULL) 1196 | return 1; 1197 | toksp = 0; 1198 | nsect = 0; 1199 | assemble(); 1200 | 1201 | /* third pass */ 1202 | fseek(tokf, 0, 0); 1203 | fseek(wf, 0, 0); 1204 | toksp = 0; 1205 | nsect = 0; 1206 | assemble(); 1207 | fclose(tokf); 1208 | fclose(wf); 1209 | 1210 | outf = fopen("a.rim", "wb"); 1211 | if(outf == NULL) 1212 | return 1; 1213 | 1214 | /* 1215 | blkstart = sects[nsect-1].start; 1216 | blksize = 0; 1217 | for(s = §s[nsect-1]; s >= sects; s--){ 1218 | printf("sect %ld: %o %o\n", s-sects, s->start, s->size); 1219 | blksize += s->size; 1220 | } 1221 | writeblock(blkstart, blksize); 1222 | dumpmem(blkstart, blkstart+blksize); 1223 | */ 1224 | for(s = §s[nsect-1]; s >= sects; s--){ 1225 | writeblock(s->start, s->size); 1226 | dumpmem(s->start, s->start+s->size); 1227 | } 1228 | if(start = findsym("START"), *start) 1229 | putw10(WORD(0254000L, (*start)->v.value), outf); 1230 | else 1231 | putw10(WORD(0254000L, origin), outf); 1232 | fclose(outf); 1233 | 1234 | dumpsymbols(); 1235 | } 1236 | --------------------------------------------------------------------------------