The LC-2200 (Little Computer 2200). The LC-2200 is very simple, but it is general enough to solve complex problems. For this homework, you will need to know the instruction set and instruction format of the LC-2200.
The LC-2200 is a 16-register, 32-bit computer. All addresses are word-addresses. By assembly-language convention, register 0 will always contain 0 (i.e. the machine will not enforce this, but no assembly-language program should ever change register 0 from its initial value of 0).
R-type instructions (add, nand):
bits 19-16: opcode
bits 15-12: reg A
bits 11-8: reg B
bits 7-4: unused (should all be 0)
bits 3-0: reg D
I-type instructions (lw, sw, beq):
bits 19-16: opcode
bits 15-12: reg A
bits 11-8: reg B
bits 7-0: offsetField (an 8-bit, 2's complement number with
a range of -128 to 127)
J-type instructions (jalr):
bits 19-16: opcode
bits 15-12: reg A
bits 11-8: reg B
bits 7-0: unused (should all be 0)
O-type instructions (halt, noop):
bits 19-16: opcode
bits 15-0: unused (should all be 0)
S-type instructions (inc, dec, addm, addi)
bits 19-16: opcode
bits 13-0 : determined by opcode (see below)
Symbolic instructions should follow the same layout.
------------------------------------------------------------------
Table 1: Description of Machine Instructions
------------------------------------------------------------------
Assembly language Opcode in binary Action
name for instruction (bits 19, 18, 17, 16)
------------------------------------------------------------------
add (R-type format) 0000 add contents of regA
with contents of regB,
store results in regD.
nand (R-type format) 0001 nand contents of regA
with contents of regB,
store results in regD.
lw (I-type format) 0010 load regB from memory.
Memory address is formed
by adding offsetField
with the contents of
regA.
sw (I-type format) 0011 store regB into memory.
Memory address is formed
by adding offsetField
with the contents of
regA.
beq (I-type format) 0100 compare the contents of
regA and regB; if they
are the same, then
branch to the address
PC+1+offsetField, where
PC is the address of the
beq instruction.
jalr (J-type format) 0101 First store PC+1 into
regB, where PC is the
address of the jalr
instruction. Then
branch to the address
now contained in regA.
Note that if regA is the
same as regB, the
processor will first
store PC+1 into that
register, then end up
branching to PC+1.
halt (O-type format) 0110 halt the machine (do
nothing and let the
simulator notice that
the machine halted).
noop (O-type format) 0111 do nothing.
inc (S-type format) 1000 Add 1 to regA and
store the result in
regD. Format:
bits 19-16: opcode
bits 15-12: regA
bits 11-4 : unused
bits 3-0 : regD
dec (S-type format) 1001 Subtract 1 from regA
and store the result
in regD. Format:
bits 19-16: opcode
bits 15-12: regA
bits 11-4 : unused
bits 3-0 : regD
addi (S-type format) 1010 Add contents of regA
to immediate and
store the result in
regB. Format:
bits 19-16: opcode
bits 15-12: regA
bits 11-8 : regB
bits 7-0 : immediate
addm (S-type format) 1011 Add contents of regB
with contents of the
memory address
formed by adding
regA to offsetField.
store the result in
regB. Format:
bits 19-16: opcode
bits 15-12: regA
bits 11-8 : regB
bits 7-0 : offsetField
-----------------------------------------------------------------------
There are two extra symbolic constructs which you may use
(address 0): .fill 5
(address 1): .fill -2
becomes
(address 0): 0x00000005
(address 1): 0xfffffffe
<label> <instruction> allows you to refers to the address
of <instruction> as <label>.
(address 0): .fill start
(address 1): start add 0 0 0
(address 2): end add 0 0 0
(address 3): beq 0 0 end
becomes
(address 0): 0x00000001
(address 1): 0x00000000
(address 2): 0x00000000
(address 3): 0x000400fe
LC-2200 Instructions:
(address 100): lw 0 1 one # r1 = 1
(address 101): lw 0 7 ten # r7 = 10
(address 102): add 1 0 6 # r6 = 1
(address 103): loop beq 1 7 end # loop while r1 != r7
(address 104): add 2 1 2 # r2 += r1
(address 105): add 1 6 1 # r1++
(address 106): beq 0 0 loop # goto loop
(address 107): end add 2 0 15 # return r2
(address 108): jalr 14 1 # jump to the callee
...
(address 125) one .fill 1
(address 126) ten .fill 10
Instruction Format:
(address 100): 2 0 0 125 [offset]
(address 101): 2 0 7 126 [offset]
(address 102): 0 1 0 6 [reg]
(address 103): 4 1 7 3 [offset]
(address 104): 0 2 1 2 [reg]
(address 105): 0 1 6 1 [reg]
(address 106): 4 0 0 -4 [offset]
(address 107): 0 2 0 15 [reg]
(address 108): 5 14 1 0 [---]
...
(address 125): 0 0 0 1 [offset]
(address 126): 0 0 0 10 [offset]
Binary and Hex:
(address 100) 0010 0000 0000 0111 1101 = 0x0002007d
(address 101) 0010 0000 0111 0111 1110 = 0x0002077e
(address 102) 0000 0001 0000 0000 0110 = 0x00001006
(address 103) 0100 0001 0111 0000 0011 = 0x00041703
(address 104) 0000 0010 0001 0000 0010 = 0x00002102
(address 105) 0000 0001 0110 0000 0001 = 0x00001601
(address 106) 0100 0000 0000 1111 1100 = 0x000400fc
(address 107) 0000 0010 0000 0000 1111 = 0x0000200f
(address 108) 0101 1110 0001 0000 0000 = 0x0005e100
...
(address 125) 0000 0000 0000 0000 0001 = 0x00000001
(address 126) 0000 0000 0000 0000 1010 = 0x0000000a
Translating the LC-2002 symbolic instructions into machine code is fairly straightfoward:
lw 0 1 five load reg1 with 5 (uses symbolic address)
lw 1 2 3 load reg2 with -1 (uses numeric address)
start add 1 2 1 decrement reg1
beq 0 1 2 goto end of program when reg1==0
beq 0 0 start go back to the beginning of the loop
noop
done halt end of program
five .fill 5
neg1 .fill -1
stAddr .fill start will contain the address of start (2)
1) Replace the symbolic labels with their numerical values
2 0 1 7 load reg1 with 5 (uses symbolic address)
2 1 2 3 load reg2 with -1 (uses numeric address)
0 1 2 1 decrement reg1
4 0 1 2 goto end of program when reg1==0
4 0 0 -3 go back to the beginning of the loop
7 0 0 0
6 0 0 0 end of program
5
-1
2
2) Translate into hexadecimal
(address 0): 0x00020107
(address 1): 0x00021203
(address 2): 0x00001201
(address 3): 0x00040102
(address 4): 0x000400fd
(address 5): 0x00070000
(address 6): 0x00060000
(address 7): 0x00000005
(address 8): 0xffffffff
(address 9): 0x00000002
PCWr: If enabled, causes PCWE to be enabled (due to the
OR gate).
PCWrC: If the bit in the condReg is zero AND this is
enabled, the PCWE is enabled.
PCdriveData: If enabled, drives the current value of the PC to
the databus.
PCdriveAddr: If enabled, drives the current value of the PC to
the address bus.
IRWE: "Instruction Register Write-Enable". If enabled,
the value driven to the data bus from some
resource in this cycle is "latched" into the IR by
the end of the current cycle.
IRdrive: If enabled, drives the current value of the IR to
the databus (through the AND gate, thus driving
only the value of the 8 bit offset field).
ALURWE: "ALU Result Write-Enable". If enabled, the value
calculated by the ALU during this cycle is "latched"
into the ALU result register by the end of the
current cycle.
ALURdriveData: If enabled, drives the current value of the ALU
result register to the databus.
ALURdriveAddr: If enabled, drives the current value of the ALU
result register to the address bus.
CRWE: "Condition Register Write-Enable". If enabled,
the value calculated by the ALU during this cycle
and "piped" through the 32-bit OR gate to become
a single bit is "latched" into the CR by the end
of the current cycle.
MemWr: If enabled (a write to RAM is desired), the
value driven to the address bus from some
resource in this cycle is "latched" into the
memory_addr_buffer and the value driven to the
databus from some resource in this cycle is
"latched" into the memory_data_buffer by the
end of the current cycle. (This causes the
actual write to occur during the NEXT cycle,
during which NO memory device control signals
may be enabled).
MemRd: If enabled (a read from RAM is desired), the
value driven to the address bus from some
resource in this cycle is "latched" into the
memory_addr_buffer by the end of the current
cycle, causing the memory device to start
the read operation (note that the RAM device
is slow, and the actual datum requested is
available on the NEXT cycle for driving to the
data bus (see below).
MemDriveData: If enabled, causes the memory datum at the
address indicated by memory_addr_buffer to
be driven onto the databus. Be careful not
to violate the memory latency limitation.
MemDriveAddr: If enabled, causes the memory datum at the
address indicated by memory_addr_buffer to
be driven onto the addrbus. Be careful not
to violate the memory latency limitation.
RegRdPE1: "Register File Enable Read From Port 1". If
enabled, causes the register indexed by RdPA1
("Read Port Address 1") to drive its value to
the "Read Data 1" port (to the databus).
RegRdPE2: "Register File Enable Read From Port 2". If
enabled, causes the register indexed by RdPA2
("Read Port Address 2") to drive its value to
the "Read Data 2" port (to the address bus).
RegWE: "Register File Write-Enable". If enabled,
the value driven to the data bus from some
resource in this cycle is "latched" into the
register indexed by WrPA ("Write Port Address")
by the end of the current cycle.
ALUop: "ALU operation". Specifies which arithmetic
operation will be performed by the ALU during
this cycle (can be: ALUnoOp, ALUaddOp, ALUsubOP,
or ALUnandOp).
ALUMUXC: "ALU MUX control". Determines the left-hand
operand of the ALU for the ALU operation performed
during this cycle (can be: ALUMUXCone, ALUMUXCbus,
or ALUMUXCsignExtend). If it is ALUMUXCsignExtend,
the left-hand operand should be determined by
sign-extending the value driven to the data bus
from some resource in this cycle. If it is
ALUMUXCbus, simply use the full 32 bit value directly
off the databus. If it is ALUMUXCone, use the
value 1 as the left-hand operand.
RdMUXC: "Register File Read Port Address 1 MUX control".
Determines which "field" of the instruction register
to use as the index RdPA1 (can be: RdMUXCregA or
RdMUXCregB).
WrMUXC: "Register File Write Port Address MUX control".
Determines which "field" of the instruction register
to use as the index WrPA (can be: WrMUXCregB or
WrMUXCregD).