243 lines
9.7 KiB
Text
243 lines
9.7 KiB
Text
|
// note that this is nearly identical to the example
|
||
|
// given in Tanenbaum. Note:
|
||
|
//
|
||
|
// 1) SlashSlash-style ("//") comment characters have been added.
|
||
|
//
|
||
|
// 2) "nop" has been added as a pseudo-instruction to indicate that
|
||
|
// nothing should be done except goto the next instruction. It
|
||
|
// is a do-nothing sub-instruction that allows us to have MAL
|
||
|
// statements without a label.
|
||
|
//
|
||
|
// 3) instructions are "anchored" to locations in the control
|
||
|
// store as defined below with the ".label" pseudo-instruction
|
||
|
//
|
||
|
// 4) a default instruction may be specified using the ".default"
|
||
|
// pseudo-instruction. This instruction is placed in all
|
||
|
// unused locations of the control store by the mic1 MAL assembler.
|
||
|
//
|
||
|
|
||
|
// labeled statements are "anchored" at the specified control store address
|
||
|
.label nop1 0x00
|
||
|
.label bipush1 0x10
|
||
|
.label ldc_w1 0x13
|
||
|
.label iload1 0x15
|
||
|
.label wide_iload1 0x115
|
||
|
.label istore1 0x36
|
||
|
.label wide_istore1 0x136
|
||
|
.label pop1 0x57
|
||
|
.label dup1 0x59
|
||
|
.label swap1 0x5F
|
||
|
.label iadd1 0x60
|
||
|
.label isub1 0x64
|
||
|
.label iand1 0x7E
|
||
|
.label iinc1 0x84
|
||
|
.label ifeq1 0x99
|
||
|
.label iflt1 0x9B
|
||
|
.label if_icmpeq1 0x9F
|
||
|
.label goto1 0xA7
|
||
|
.label ireturn1 0xAC
|
||
|
.label ior1 0xB0
|
||
|
.label invokevirtual1 0xB6
|
||
|
.label wide1 0xC4
|
||
|
.label halt1 0xFF
|
||
|
.label err1 0xFE
|
||
|
.label out1 0xFD
|
||
|
.label in1 0xFC
|
||
|
.label jifeven1 0x42
|
||
|
|
||
|
// default instruction to place in any unused addresses of the control store
|
||
|
.default goto err1
|
||
|
|
||
|
Main1 PC = PC + 1; fetch; goto (MBR) // MBR holds opcode; get next byte; dispatch
|
||
|
|
||
|
nop1 goto Main1 // Do nothing
|
||
|
|
||
|
iadd1 MAR = SP = SP - 1; rd // Read in next-to-top word on stack
|
||
|
iadd2 H = TOS // H = top of stack
|
||
|
iadd3 MDR = TOS = MDR + H; wr; goto Main1 // Add top two words; write to top of stack
|
||
|
|
||
|
isub1 MAR = SP = SP - 1; rd // Read in next-to-top word on stack
|
||
|
isub2 H = TOS // H = top of stack
|
||
|
isub3 MDR = TOS = MDR - H; wr; goto Main1 // Do subtraction; write to top of stack
|
||
|
|
||
|
iand1 MAR = SP = SP - 1; rd // Read in next-to-top word on stack
|
||
|
iand2 H = TOS // H = top of stack
|
||
|
iand3 MDR = TOS = MDR AND H; wr; goto Main1 // Do AND; write to new top of stack
|
||
|
|
||
|
ior1 MAR = SP = SP - 1; rd // Read in next-to-top word on stack
|
||
|
ior2 H = TOS // H = top of stack
|
||
|
ior3 MDR = TOS = MDR OR H; wr; goto Main1 // Do OR; write to new top of stack
|
||
|
|
||
|
dup1 MAR = SP = SP + 1 // Increment SP and copy to MAR
|
||
|
dup2 MDR = TOS; wr; goto Main1 // Write new stack word
|
||
|
|
||
|
pop1 MAR = SP = SP - 1; rd // Read in next-to-top word on stack
|
||
|
pop2 // Wait for new TOS to be read from memory
|
||
|
pop3 TOS = MDR; goto Main1 // Copy new word to TOS
|
||
|
|
||
|
swap1 MAR = SP - 1; rd // Set MAR to SP - 1; read 2nd word from stack
|
||
|
swap2 MAR = SP // Set MAR to top word
|
||
|
swap3 H = MDR; wr // Save TOS in H; write 2nd word to top of stack
|
||
|
swap4 MDR = TOS // Copy old TOS to MDR
|
||
|
swap5 MAR = SP - 1; wr // Set MAR to SP - 1; write as 2nd word on stack
|
||
|
swap6 TOS = H; goto Main1 // Update TOS
|
||
|
|
||
|
bipush1 SP = MAR = SP + 1 // MBR = the byte to push onto stack
|
||
|
bipush2 PC = PC + 1; fetch // Increment PC, fetch next opcode
|
||
|
bipush3 MDR = TOS = MBR; wr; goto Main1 // Sign-extend constant and push on stack
|
||
|
|
||
|
|
||
|
iload1 H = LV // MBR contains index; copy LV to H
|
||
|
iload2 MAR = MBRU + H; rd // MAR = address of local variable to push
|
||
|
iload3 MAR = SP = SP + 1 // SP points to new top of stack; prepare write
|
||
|
iload4 PC = PC + 1; fetch; wr // Inc PC; get next opcode; write top of stack
|
||
|
iload5 TOS = MDR; goto Main1 // Update TOS
|
||
|
|
||
|
istore1 H = LV // MBR contains index; Copy LV to H
|
||
|
istore2 MAR = MBRU + H // MAR = address of local variable to store into
|
||
|
istore3 MDR = TOS; wr // Copy TOS to MDR; write word
|
||
|
istore4 SP = MAR = SP - 1; rd // Read in next-to-top word on stack
|
||
|
istore5 PC = PC + 1; fetch // Increment PC; fetch next opcode
|
||
|
istore6 TOS = MDR; goto Main1 // Update TOS
|
||
|
wide1 PC = PC + 1; fetch; goto (MBR OR 0x100) // Multiway branch with high bit set
|
||
|
|
||
|
wide_iload1 PC = PC + 1; fetch // MBR contains 1st index byte; fetch 2nd
|
||
|
wide_iload2 H = MBRU << 8 // H = 1st index byte shifted left 8 bits
|
||
|
wide_iload3 H = MBRU OR H // H = 16-bit index of local variable
|
||
|
wide_iload4 MAR = LV + H; rd; goto iload3 // MAR = address of local variable to push
|
||
|
|
||
|
wide_istore1 PC = PC + 1; fetch // MBR contains 1st index byte; fetch 2nd
|
||
|
wide_istore2 H = MBRU << 8 // H = 1st index byte shifted left 8 bits
|
||
|
wide_istore3 H = MBRU OR H // H = 16-bit index of local variable
|
||
|
wide_istore4 MAR = LV + H; goto istore3 // MAR = address of local variable to store into
|
||
|
|
||
|
ldc_w1 PC = PC + 1; fetch // MBR contains 1st index byte; fetch 2nd
|
||
|
ldc_w2 H = MBRU << 8 // H = 1st index byte << 8
|
||
|
ldc_w3 H = MBRU OR H // H = 16-bit index into constant pool
|
||
|
ldc_w4 MAR = H + CPP; rd; goto iload3 // MAR = address of constant in pool
|
||
|
|
||
|
iinc1 H = LV // MBR contains index; Copy LV to H
|
||
|
iinc2 MAR = MBRU + H; rd // Copy LV + index to MAR; Read variable
|
||
|
iinc3 PC = PC + 1; fetch // Fetch constant
|
||
|
iinc4 H = MDR // Copy variable to H
|
||
|
iinc5 PC = PC + 1; fetch // Fetch next opcode
|
||
|
iinc6 MDR = MBR + H; wr; goto Main1 // Put sum in MDR; update variable
|
||
|
|
||
|
goto1 OPC = PC - 1 // Save address of opcode.
|
||
|
goto2 PC = PC + 1; fetch // MBR = 1st byte of offset; fetch 2nd byte
|
||
|
goto3 H = MBR << 8 // Shift and save signed first byte in H
|
||
|
goto4 H = MBRU OR H // H = 16-bit branch offset
|
||
|
goto5 PC = OPC + H; fetch // Add offset to OPC
|
||
|
goto6 goto Main1 // Wait for fetch of next opcode
|
||
|
|
||
|
iflt1 MAR = SP = SP - 1; rd // Read in next-to-top word on stack
|
||
|
iflt2 OPC = TOS // Save TOS in OPC temporarily
|
||
|
iflt3 TOS = MDR // Put new top of stack in TOS
|
||
|
iflt4 N = OPC; if (N) goto T; else goto F // Branch on N bit
|
||
|
|
||
|
ifeq1 MAR = SP = SP - 1; rd // Read in next-to-top word of stack
|
||
|
ifeq2 OPC = TOS // Save TOS in OPC temporarily
|
||
|
ifeq3 TOS = MDR // Put new top of stack in TOS
|
||
|
ifeq4 Z = OPC; if (Z) goto T; else goto F // Branch on Z bit
|
||
|
|
||
|
if_icmpeq1 MAR = SP = SP - 1; rd // Read in next-to-top word of stack
|
||
|
if_icmpeq2 MAR = SP = SP - 1 // Set MAR to read in new top-of-stack
|
||
|
if_icmpeq3 H = MDR; rd // Copy second stack word to H
|
||
|
if_icmpeq4 OPC = TOS // Save TOS in OPC temporarily
|
||
|
if_icmpeq5 TOS = MDR // Put new top of stack in TOS
|
||
|
if_icmpeq6 Z = OPC - H; if (Z) goto T; else goto F // If top 2 words are equal, goto T, else goto F
|
||
|
|
||
|
T OPC = PC - 1; fetch; goto goto2 // Same as goto1; needed for target address
|
||
|
|
||
|
F PC = PC + 1 // Skip first offset byte
|
||
|
F2 PC = PC + 1; fetch // PC now points to next opcode
|
||
|
F3 goto Main1 // Wait for fetch of opcode
|
||
|
|
||
|
invokevirtual1 PC = PC + 1; fetch // MBR = index byte 1; inc. PC, get 2nd byte
|
||
|
invokevirtual2 H = MBRU << 8 // Shift and save first byte in H
|
||
|
invokevirtual3 H = MBRU OR H // H = offset of method pointer from CPP
|
||
|
invokevirtual4 MAR = CPP + H; rd // Get pointer to method from CPP area
|
||
|
invokevirtual5 OPC = PC + 1 // Save Return PC in OPC temporarily
|
||
|
invokevirtual6 PC = MDR; fetch // PC points to new method; get param count
|
||
|
invokevirtual7 PC = PC + 1; fetch // Fetch 2nd byte of parameter count
|
||
|
invokevirtual8 H = MBRU << 8 // Shift and save first byte in H
|
||
|
invokevirtual9 H = MBRU OR H // H = number of parameters
|
||
|
invokevirtual10 PC = PC + 1; fetch // Fetch first byte of # locals
|
||
|
invokevirtual11 TOS = SP - H // TOS = address of OBJREF - 1
|
||
|
invokevirtual12 TOS = MAR = TOS + 1 // TOS = address of OBJREF (new LV)
|
||
|
invokevirtual13 PC = PC + 1; fetch // Fetch second byte of # locals
|
||
|
invokevirtual14 H = MBRU << 8 // Shift and save first byte in H
|
||
|
invokevirtual15 H = MBRU OR H // H = # locals
|
||
|
invokevirtual16 MDR = SP + H + 1; wr // Overwrite OBJREF with link pointer
|
||
|
invokevirtual17 MAR = SP = MDR; // Set SP, MAR to location to hold old PC
|
||
|
invokevirtual18 MDR = OPC; wr // Save old PC above the local variables
|
||
|
invokevirtual19 MAR = SP = SP + 1 // SP points to location to hold old LV
|
||
|
invokevirtual20 MDR = LV; wr // Save old LV above saved PC
|
||
|
invokevirtual21 PC = PC + 1; fetch // Fetch first opcode of new method.
|
||
|
invokevirtual22 LV = TOS; goto Main1 // Set LV to point to LV Frame
|
||
|
|
||
|
ireturn1 MAR = SP = LV; rd // Reset SP, MAR to get link pointer
|
||
|
ireturn2 // Wait for read
|
||
|
ireturn3 LV = MAR = MDR; rd // Set LV to link ptr; get old PC
|
||
|
ireturn4 MAR = LV + 1 // Set MAR to read old LV
|
||
|
ireturn5 PC = MDR; rd; fetch // Restore PC; fetch next opcode
|
||
|
ireturn6 MAR = SP // Set MAR to write TOS
|
||
|
ireturn7 LV = MDR // Restore LV
|
||
|
ireturn8 MDR = TOS; wr; goto Main1 // Save return value on original top of stack
|
||
|
|
||
|
halt1 goto halt1
|
||
|
|
||
|
err1 OPC=H=-1
|
||
|
OPC=H+OPC
|
||
|
MAR=H+OPC // compute IO address
|
||
|
OPC=H=1 // 1
|
||
|
OPC=H=H+OPC // 10
|
||
|
OPC=H=H+OPC // 100
|
||
|
OPC=H=H+OPC // 1000
|
||
|
OPC=H=H+OPC+1 // 10001
|
||
|
OPC=H=H+OPC // 100010
|
||
|
MDR=H+OPC+1;wr // 1000101 'E'
|
||
|
OPC=H=1 // 1
|
||
|
OPC=H=H+OPC // 10
|
||
|
OPC=H=H+OPC+1 // 101
|
||
|
OPC=H=H+OPC // 1010
|
||
|
OPC=H=H+OPC // 10100
|
||
|
OPC=H=H+OPC+1 // 101001
|
||
|
MDR=H+OPC;wr // 1010010 'R'
|
||
|
nop
|
||
|
MDR=H+OPC;wr // 1010010 'R'
|
||
|
OPC=H=1 // 1
|
||
|
OPC=H=H+OPC // 10
|
||
|
OPC=H=H+OPC // 100
|
||
|
OPC=H=H+OPC+1 // 1001
|
||
|
OPC=H=H+OPC+1 // 10011
|
||
|
OPC=H=H+OPC+1 // 100111
|
||
|
MDR=H+OPC+1;wr // 1001111 'O'
|
||
|
OPC=H=1 // 1
|
||
|
OPC=H=H+OPC // 10
|
||
|
OPC=H=H+OPC+1 // 101
|
||
|
OPC=H=H+OPC // 1010
|
||
|
OPC=H=H+OPC // 10100
|
||
|
OPC=H=H+OPC+1 // 101001
|
||
|
MDR=H+OPC;wr // 1010010 'R'
|
||
|
goto halt1
|
||
|
|
||
|
out1 OPC=H=-1
|
||
|
OPC=H+OPC
|
||
|
MAR=H+OPC // compute OUT address
|
||
|
MDR=TOS; wr // write to output
|
||
|
nop
|
||
|
MAR=SP=SP-1; rd // decrement stack pointer
|
||
|
nop
|
||
|
TOS=MDR; goto Main1
|
||
|
|
||
|
in1 OPC=H=-1
|
||
|
OPC=H+OPC
|
||
|
MAR=H+OPC;rd // compute IN address ; read from input
|
||
|
MAR=SP=SP+1 // increment SP; wait for read
|
||
|
TOS=MDR;wr ; goto Main1 // Write
|
||
|
|
||
|
jifeven1 H = 1
|
||
|
jifeven2 Z = TOS AND H; if (Z) goto T; else goto F
|
||
|
|