CPSC 3300 - Spring 2018 - Project 2 Assignment [if using this assignment again in the future: (1) make sure the difference between the instruction-level simulator and this microinstruction-level simulator is clear; (2) output of this simulator should be something like this: cycle-by-cycle results: initial microcounter is displayed along with microinstruction, updated microcounter, updated datapath register values, and finally names of active control signals for fields other than ja in the microinstruction, the title is listed in column format, e.g., the first signal is "ip" -- microinstruction --- --cntl signals-- -mh -- active ilel--lelele--el cal -- next --- datapath registers --- control uc pppmrwddiiaaasub dpt ja uc pc mar mdr acc alu b ir signals 00: 0011000000000000 000 01 01 0 0 0 0 0 0 0 ep lm 01: 0000100000000000 000 02 02 0 0 107 0 0 0 0 r 02: 1000000110000000 010 00 03 1 0 107 0 0 0 107 ip ed li map 03: 0001000001000000 000 04 04 1 7 107 0 0 0 107 lm ei 04: 0000100000000000 000 05 05 1 7 2 0 0 0 107 r 05: 0000000100100000 000 00 00 1 7 2 2 0 0 107 ed la ] Due date: before midnight on the night of Thursday, March 15 Submission: use handin.cs.clemson.edu to turn in three files: 1) source code for the simulator 2) addr.txt for the extended instruction set 2) uprog.txt for the extended instruction set Grading standard: correctness of simulator for basic inst. set (85%); correctness of microroutines for extended inst. set (15%) Late penalty: 10% off per day late, up to five days Tools needed: gcc (or other language) Concepts needed: processor simulation, microcode This can be an individual assignment or a team of two assignment. SIMULATOR Write a program that simulates the simple microprogrammed machine described by Richard Eckert in "Micro-programmed versus hardwired control units: How computers really work," which is available online as http://www.cs.binghamton.edu/~reckert/hardwire3new.html The program can be written in any language, but it will be tested and must run on one of the School of Computing Ubuntu 16.04 Linux systems. (Do not compile or run on access.cs.clemson.edu; ssh into one of the lab machines to compile and run, e.g., on one of the joeys). An example instruction is: +----+--------+ memory-word |0001|00100100| represented in hex as 124 +----+--------+ 11 bit # 0123 45678901 where bits 0-3 == 4-bit opcode bits 4-11 == 8-bit address field The basic instruction set is: lda - load accumulator, coded as 1xx, where xx is the operand address sta - store accumulator, coded as 2xx, where xx is the destination address add - add value in b register to accumulator, coded as 3yy, where yy is ignored sub - subtract value in b register from accumulator, coded as 4yy, where yy is ignored mba - make b register same as accumulator (i.e., copy the value in the accumulator into the b register), coded as 5yy, where yy is ignored jmp - unconditional jump, coded as 6xx, where xx is the branch target address jn (jneg) - conditional jump, coded as 7xx, where xx is the branch target address hlt - halt, coded as any value 800 to fff, inclusive An opcode of 0 generates an error message and causes an exit from the simulator. Execution of the machine language program always starts at address 0, and the halt instruction means halt the simulation. (If you want data to be located at low addresses, the instruction at location 0 should be an unconditional jump to the entry point of the main program.) For the datapath of the simulated computer, there should be: two 8-bit registers: PC, MAR five 12-bit registers: IR, MDR, ACC, B, ALU_TMP and for the microprogrammed control: 32 x 24-bit control ROM 16 x 5-bit address ROM 5-bit microinstruction counter 24-bit microinstruction register 12-bit bus and for the memory: 256 x 12-bit main memory (called RAM by Eckert) The microinstruction format is the same as that given in Table 4 of the Eckert paper. +----------------+---+-----+ cs-word |0011000000000000|000|00001| represented in hex as 300001 +----------------+---+-----+ 111111 111 12222 bit # 0123456789012345 678 90123 where bit 0 == IP: increment PC bit 1 == LP: load PC bit 2 == EP: enable PC bit 3 == LM: load MAR bit 4 == R: read bit 5 == W: write bit 6 == LD: load MDR bit 7 == ED: enable MDR bit 8 == LI: load IR bit 9 == EI: enable IR bit 10 == LA: load accumulator bit 11 == EA: enable accumulator bit 12 == A: add bit 13 == S: subtract bit 14 == EU: enable ALU temporary register bit 15 == LB: load B register bit 16 == CD: perform a conditional jump bit 17 == MAP: use address ROM to map opcode in IR to starting address of microroutine bit 18 == HLT: halt bits 19-23 == 5-bit CRJA: control ROM jump address The instructions and data are read as hex values from a file named "ram.txt" in the current directory. The number of hex values in ram.txt can vary from one (e.g., a single halt instruction) to at most 256. The main memory locations that are not initialized by values read from ram.txt should be initialized to zero. The starting addresses of the microroutines are read as 16 hex values from a file named "addr.txt" in the current directory, and the microprogram is read as 32 hex values from a file named "uprog.txt" in the current directory. Your simulator should first show the contents of main memory, the contents of the address ROM, and the contents of the control ROM as they are read in before the simulation begins. During simulation, your simulator should show the cycle-by-cycle operations of the simple machine, based on the control signals in the current microinstruction. When the simulation ends by the execution of a halt instruction, your simulator should again show the contents of main memory so that any changes to memory words caused by store instructions can be verified. (There is no need to show all 256 memory words. Use the count of values read in from ram.txt to control how many memory words are displayed. Note: this means that if you wish to verify the effect of a store instruction on a memory word, you must include that memory word in the ram.txt initialization.) The control signals should be processed in this order: enable signals: EP, ED, EI, EA, EU memory operations: R, W ALU operations: A, S load signals: LP, LM, LD, LI, LA, LB increment PC signal: IP microinstruction counter: CD, CRJA opcode mapping: MAP halt signal: HLT E.g., we are breaking up the numerous possible enable/load register transfer pairs into decoupled steps using the bus variable: 1) first process the enable signal to copy the contents of a source register to the internal datapath bus; 2) then process the load signal to copy the contents of the bus into the destination register. For the three following input files for the basic instruction set: ---ram.txt--- 608 1 2 0 5 0 0 0 101 500 102 300 203 500 400 104 500 103 400 205 716 206 800 ---addr.txt--- 0 3 6 9 b d e f 1f 1f 1f 1f 1f 1f 1f 1f ---uprog.txt--- 300001 080002 818040 104004 080005 012000 104007 021008 040000 00080a 002200 00040c 002200 001100 404000 000091 000000 404000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 ffffff 000020 The simulator output is: microprogram simulation of Eckert's simple machine (all values are shown in hexadecimal) contents of RAM memory addr value 0: 608 1: 001 2: 002 3: 000 4: 005 5: 000 6: 000 7: 000 8: 101 9: 500 a: 102 b: 300 c: 203 d: 500 e: 400 f: 104 10: 500 11: 103 12: 400 13: 205 14: 716 15: 206 16: 800 contents of address ROM opc addr 0: 00 1: 03 2: 06 3: 09 4: 0b 5: 0d 6: 0e 7: 0f 8: 1f 9: 1f a: 1f b: 1f c: 1f d: 1f e: 1f f: 1f contents of control ROM with active signals identified addr contents 0: 300001 ep lm crja=01 1: 080002 r crja=02 2: 818040 ip ed li map crja=00 3: 104004 lm ei crja=04 4: 080005 r crja=05 5: 012000 ed la crja=00 6: 104007 lm ei crja=07 7: 021008 ld ea crja=08 8: 040000 w crja=00 9: 00080a a crja=0a a: 002200 la eu crja=00 b: 00040c s crja=0c c: 002200 la eu crja=00 d: 001100 ea lb crja=00 e: 404000 lp ei crja=00 f: 000091 cd crja=11 10: 000000 crja=00 11: 404000 lp ei crja=00 12: 000000 crja=00 13: 000000 crja=00 14: 000000 crja=00 15: 000000 crja=00 16: 000000 crja=00 17: 000000 crja=00 18: 000000 crja=00 19: 000000 crja=00 1a: 000000 crja=00 1b: 000000 crja=00 1c: 000000 crja=00 1d: 000000 crja=00 1e: ffffff ip lp ep lm r w ld ed li ei la ea a s eu lb cd map hlt crja=1f 1f: 000020 hlt crja=00 intial register values pc mar mdr acc alu b ir 0 0 0 0 0 0 0 control signals and register values after each microinstruction mh ilelrwleleleasel cal uc pppm ddiiaa ub dpt ja pc mar mdr acc alu b ir 01 0011000000000000 000 01 0 0 0 0 0 0 0 ep lm 02 0000100000000000 000 02 0 0 608 0 0 0 0 r 0e 1000000110000000 010 00 1 0 608 0 0 0 608 ip ed li map 00 0100000001000000 000 00 8 0 608 0 0 0 608 lp ei 01 0011000000000000 000 01 8 8 608 0 0 0 608 ep lm 02 0000100000000000 000 02 8 8 101 0 0 0 608 r 03 1000000110000000 010 00 9 8 101 0 0 0 101 ip ed li map 04 0001000001000000 000 04 9 1 101 0 0 0 101 lm ei 05 0000100000000000 000 05 9 1 1 0 0 0 101 r 00 0000000100100000 000 00 9 1 1 1 0 0 101 ed la 01 0011000000000000 000 01 9 9 1 1 0 0 101 ep lm 02 0000100000000000 000 02 9 9 500 1 0 0 101 r 0d 1000000110000000 010 00 a 9 500 1 0 0 500 ip ed li map 00 0000000000010001 000 00 a 9 500 1 0 1 500 ea lb 01 0011000000000000 000 01 a a 500 1 0 1 500 ep lm 02 0000100000000000 000 02 a a 102 1 0 1 500 r 03 1000000110000000 010 00 b a 102 1 0 1 102 ip ed li map 04 0001000001000000 000 04 b 2 102 1 0 1 102 lm ei 05 0000100000000000 000 05 b 2 2 1 0 1 102 r 00 0000000100100000 000 00 b 2 2 2 0 1 102 ed la 01 0011000000000000 000 01 b b 2 2 0 1 102 ep lm 02 0000100000000000 000 02 b b 300 2 0 1 102 r 09 1000000110000000 010 00 c b 300 2 0 1 300 ip ed li map 0a 0000000000001000 000 0a c b 300 2 3 1 300 a 00 0000000000100010 000 00 c b 300 3 3 1 300 la eu 01 0011000000000000 000 01 c c 300 3 3 1 300 ep lm 02 0000100000000000 000 02 c c 203 3 3 1 300 r 06 1000000110000000 010 00 d c 203 3 3 1 203 ip ed li map 07 0001000001000000 000 07 d 3 203 3 3 1 203 lm ei 08 0000001000010000 000 08 d 3 3 3 3 1 203 ld ea 00 0000010000000000 000 00 d 3 3 3 3 1 203 w 01 0011000000000000 000 01 d d 3 3 3 1 203 ep lm 02 0000100000000000 000 02 d d 500 3 3 1 203 r 0d 1000000110000000 010 00 e d 500 3 3 1 500 ip ed li map 00 0000000000010001 000 00 e d 500 3 3 3 500 ea lb 01 0011000000000000 000 01 e e 500 3 3 3 500 ep lm 02 0000100000000000 000 02 e e 400 3 3 3 500 r 0b 1000000110000000 010 00 f e 400 3 3 3 400 ip ed li map 0c 0000000000000100 000 0c f e 400 3 0 3 400 s 00 0000000000100010 000 00 f e 400 0 0 3 400 la eu 01 0011000000000000 000 01 f f 400 0 0 3 400 ep lm 02 0000100000000000 000 02 f f 104 0 0 3 400 r 03 1000000110000000 010 00 10 f 104 0 0 3 104 ip ed li map 04 0001000001000000 000 04 10 4 104 0 0 3 104 lm ei 05 0000100000000000 000 05 10 4 5 0 0 3 104 r 00 0000000100100000 000 00 10 4 5 5 0 3 104 ed la 01 0011000000000000 000 01 10 10 5 5 0 3 104 ep lm 02 0000100000000000 000 02 10 10 500 5 0 3 104 r 0d 1000000110000000 010 00 11 10 500 5 0 3 500 ip ed li map 00 0000000000010001 000 00 11 10 500 5 0 5 500 ea lb 01 0011000000000000 000 01 11 11 500 5 0 5 500 ep lm 02 0000100000000000 000 02 11 11 103 5 0 5 500 r 03 1000000110000000 010 00 12 11 103 5 0 5 103 ip ed li map 04 0001000001000000 000 04 12 3 103 5 0 5 103 lm ei 05 0000100000000000 000 05 12 3 3 5 0 5 103 r 00 0000000100100000 000 00 12 3 3 3 0 5 103 ed la 01 0011000000000000 000 01 12 12 3 3 0 5 103 ep lm 02 0000100000000000 000 02 12 12 400 3 0 5 103 r 0b 1000000110000000 010 00 13 12 400 3 0 5 400 ip ed li map 0c 0000000000000100 000 0c 13 12 400 3 ffe 5 400 s 00 0000000000100010 000 00 13 12 400 ffe ffe 5 400 la eu 01 0011000000000000 000 01 13 13 400 ffe ffe 5 400 ep lm 02 0000100000000000 000 02 13 13 205 ffe ffe 5 400 r 06 1000000110000000 010 00 14 13 205 ffe ffe 5 205 ip ed li map 07 0001000001000000 000 07 14 5 205 ffe ffe 5 205 lm ei 08 0000001000010000 000 08 14 5 ffe ffe ffe 5 205 ld ea 00 0000010000000000 000 00 14 5 ffe ffe ffe 5 205 w 01 0011000000000000 000 01 14 14 ffe ffe ffe 5 205 ep lm 02 0000100000000000 000 02 14 14 716 ffe ffe 5 205 r 0f 1000000110000000 010 00 15 14 716 ffe ffe 5 716 ip ed li map 11 0000000000000000 100 11 15 14 716 ffe ffe 5 716 cd 00 0100000001000000 000 00 16 14 716 ffe ffe 5 716 lp ei 01 0011000000000000 000 01 16 16 716 ffe ffe 5 716 ep lm 02 0000100000000000 000 02 16 16 800 ffe ffe 5 716 r 1f 1000000110000000 010 00 17 16 800 ffe ffe 5 800 ip ed li map 00 0000000000000000 001 00 17 16 800 ffe ffe 5 800 hlt contents of RAM memory addr value 0: 608 1: 001 2: 002 3: 003 4: 005 5: ffe 6: 000 7: 000 8: 101 9: 500 a: 102 b: 300 c: 203 d: 500 e: 400 f: 104 10: 500 11: 103 12: 400 13: 205 14: 716 15: 206 16: 800 MICROCODE FOR EXTENDED INSTRUCTION SET The second part of this assignment is to extend the instruction set of the simple machine by adding three additional instructions. This will require changes to addr.txt and uprog.txt; however, there should be no changes to your simulator since these three instructions can be implemented using existing registers and existing control signals. The extended instruction set is: ldc - load constant into accumulator, coded as azz, where a is the hex opcode and zz is an unsigned 8-bit value. This instruction is called load immediate or load address in other computers. The purpose is to use the 8-bit address field to hold a constant rather than a memory address. The 8-bit constant is then moved into the 12-bit accumulator without a data memory read. Because of the way EI is defined, the high-four bits of the accumulator will be set to zero. Thus only non-negative constants in the range of 00 to ff can be moved into the accumulator with this instruction. E.g., a00 will move 000 (zero) into the accumulator, and aff will move 0ff into the accumulator. ldi - load indirect to accumulator, coded as bxx, where b is the hex opcode and xx is the address of a memory word that contains the 8-bit address of the operand to be loaded. This instruction treats the memory word at the address specified in the instruction as a pointer. Thus, a level of indirection is added. Note that because memory addresses are only eight bits in width, only the low eight bits of the pointer value will be used. E.g., let the memory word at hex address 20 hold the value 456, and let the memory word at hex address 56 hold the value 123. Then the instruction encoded as b20 will load 123 into the accumulator. (Note that there is no memory word at hex address 456 since the range of memory addresses in the simple machine in hex is 00 to ff.) sti - store indirect, coded as cxx, where c is the hex opcode and xx is the address of a memory word that contains the 8-bit destination address. E.g., let the memory word at hex address 30 hold the value 234, and let the accumulator hold the value abc. Then the instruction encoded as c30 will store abc into the memory word at address 34. (Note that there is no memory word at hex address 234 since the range of memory addresses in the simple machine in hex is 00 to ff.) The hlt (halt) instruction is now coded as two ranges: any value 800 to 9ff, and any value d00 to fff, inclusive. The terminology in some other computers for the set of load/store instructions you are making available is: extended Eckert other computers action inst. set ldc load immediate ACC <- constant lda load direct ACC <- memory[addr] ldi load indirect ACC <- memory[memory[addr]] sta store direct memory[addr] <- ACC sti store indirect memory[memory[addr]] <- ACC Consider the following program that uses the new instructions: a10 // 00: ldi 10 20c // 01: sta res0 108 // 02: lda in1 20d // 03: sta res1 b0a // 04: ldi ptr_x 20e // 05: sta res2 c0b // 06: sti ptr_y 800 // 07: hlt 20 // in1: 08: 20 30 // in2: 09: 30 9 // ptr_x: 0a: 9 -- adddress of in2 f // ptr_y: 0b: f -- address of res3 0 // res0: 0c: 0 0 // res1: 0d: 0 0 // res2: 0e: 0 0 // res3: 0f: 0 For this program, ram.txt is: a10 20c 108 20d b0a 20e c0b 800 20 30 9 f 0 0 0 0 and the final memory contents as displayed by the simulator should be: contents of RAM memory addr value 0: a10 1: 20c 2: 108 3: 20d 4: b0a 5: 20e 6: c0b 7: 800 8: 020 9: 030 a: 009 b: 00f c: 010 d: 020 e: 030 f: 030