Monday, November 9, 2020

CARDIAC Simulation using PC/370 - Part 4

CARDIAC Simulation - Part 1 - Introduction to CARDIAC 

CARDIAC Simulation - Part 2 - Primary Logic/Architecture

CARDIAC Simulation - Part 3 - Memory Design / Management

CARDIAC Simulation - Part 4 - CARDIAC Instruction Set Processing

Here's the fourth & final installment of my CARDIAC Simulator project. The program TDCPU.ALC took about a day in total - design/development/testing. It took much longer to formulate this blog post - complete with the 3D stickman & computer hardware - than the actual PC/370 programming.

  

Above: CARDIAC Simulator Animation - Program Flow in Action.

The animation above demonstrates the program flow along with the cell & internal register updates (i.e. program counter/accumulator) along with display fields for the instruction, reader & output. The asterisk (*) tracks the program counter which, for the purposes of my simulator, I have always defaulted to cell 10. This leaves the first column (under 00) for program variables.

CARDIAC Instruction Set

Opcode  Mnemonic  Operation
======  ========  ===================================================
0       INP       Read a card into memory
1       CLA       Clear accumulator and add from memory (load)
2       ADD       Add from memory to accumulator
3       TAC       Test accumulator and jump if negative
4       SFT       Shift accumulator
5       OUT       Write memory location to output card
6       STO       Store accumulator to memory
7       SUB       Subtract memory from accumulator
8       JMP       Jump and save PC
9       HRS       Halt and reset
======  ========  ===================================================

CARDIAC Operation Table

The <F1> STEP key searches for the proper operational routine for the current Opcode & branches to it. Upon return it loops back, displays the screen & accepts the next keyboard input.

*---------------------------------------------------------------------*
*        CARDIAC OPERATIONS/ROUTINES                                  *
*---------------------------------------------------------------------*
OPTAB    DS    0F                            OPERATION TABLE
         DC    C'0',C'INP',A(@INP)           0-INP-READ INPUT
         DC    C'1',C'CLA',A(@CLA)           1-CLA-CLEAR ACC FROM MEM
         DC    C'2',C'ADD',A(@ADD)           2-ADD-TO ACC FROM MEM
         DC    C'3',C'TAC',A(@TAC)           3-TAC-TEST ACC/JMP NEG
         DC    C'4',C'SFT',A(@SFT)           4-SFT-SHIFT ACC L/R
         DC    C'5',C'OUT',A(@OUT)           5-OUT-WRITE MEM TO OUT
         DC    C'6',C'STO',A(@STO)           6-STO-STORE ACC TO MEM
         DC    C'7',C'SUB',A(@SUB)           7-SUB-MEM FROM ACC
         DC    C'8',C'JMP',A(@JMP)           8-JMP-JUMP/SAVE PC99
         DC    C'9',C'HRS',A(@HRS)           9-HRS-HALT/RESET
         DC    X'FF'                         END OF TABLE
*---------------------------------------------------------------------*

Now for the individual instruction routines. Each component performs a very simple function - mostly reading or writing the cell values or updating the program counter & accumulator.

0: INP - Read Card into Memory Location

The INP instruction reads the next value contained in the input card deck. In this case the deck is the DTAB table that contains our data values. As a data record is read the value is placed in the cell specified by the operand. The DTAB pointer (DPTR) is also incremented (for the next read) & the value is presented on the screen in the SCRRDR variable.

***********************************************************************
*        0:INP - READ CARD INTO MEMORY LOCATION                       *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
@INP     EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         L     8,DPTR                        LOAD DECK POINTER
         CLI   0(8),X'FF'                    END OF TABLE??
         BE    @INPX                         YES - EXIT ROUTING
*
         LA    5,62                          LOAD SCRRDR COUNT
         LA    6,SCRRDR+61                   LOAD SCRRDR OFFSET
@INPRDR  EQU   *
         MVC   4(1,6),0(6)                   BUMP READER ENTRIES
         SH    6,=H'1'                       DECREMENT SCRRDR PTR
         BCT   5,@INPRDR                     LOOP UNTIL COMPLETE
*
         MVC   SCRRDR(3),0(8)                MOVE DECK ENTRY
         C     8,=A(DTAB)                    FIRST DECK ENTRY?
         BE    *+8                           YES - BYPASS COMMA
         MVI   SCRRDR+3,C','                 MOVE COMMA DELIMITER
*
         LA    7,MEMTAB                      LOAD MEMORY ADDRESS
         PACK  DUBB,XOPER                    MOVE TARGET OPERAND
         CVB   3,DUBB                        CONVERT TO BINARY
         MH    3,=H'8'                       MULTIPLY BY LENGTH
         AR    7,3                           ADJUST MEMORY PTR
         MVC   0(3,7),0(8)                   MOVE DECK ENTRY TO CELL
*
         LA    8,6(,8)                       BUMP DECK POINTER
         ST    8,DPTR                        STORE DECK POINTER
@INPX    EQU   *
         L     6,@INP-4                      RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************

1: CLA - Clear Accumulator & Add From Memory

The CLA instruction clears the accumulator & effectively replaces it with the value contained in the cell specified by the operand. Since there is only one accumulator it's value may need to be stored, cleared & reloaded on multiple occasions. That is the nature of this simple CPU.

***********************************************************************
*        1:CLA - CLEAR ACCUMULATOR & ADD FROM MEMORY                  *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
@CLA     EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         LA    7,MEMTAB                      LOAD MEMORY ADDRESS
         PACK  DUBB,XOPER                    MOVE TARGET OPERAND
         CVB   3,DUBB                        CONVERT TO BINARY
         MH    3,=H'8'                       MULTIPLY BY LENGTH
         AR    7,3                           ADJUST MEMORY PTR
*
         ZAP   XACC,=P'0'                    CLEAR ACCUM PACKED
         MVC   XACCU(4),=CL4'0000'           CLEAR ACCUM CHAR
         CLI   0(7),C'-'                     NEGATIVE SIGN?
         BE    @CLANEG                       YES - HANDLE NEGATIVE        
@CLAPOS  EQU   *
         MVC   XACCU+1(3),0(7)               MOVE CELL DATA
         PACK  XACC,XACCU                    PACK ACCUMULATOR
         B     @CLAX                         EXIT ROUTINE PLEASE
@CLANEG  EQU   *
         MVC   XACCU+2(2),1(7)               MOVE CELL DATA
         PACK  XACC,XACCU                    PACK ACCUMULATOR
         NI    XACC+2,X'F0'                  TURN OFF SIGN BITS
         OI    XACC+2,X'0D'                  SET NEGATIVE SIGN
         MVI   XACCU,C'-'                    SET NEGATIVE CHAR
@CLAX    EQU   *
         L     6,@CLA-4                      RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************

2: ADD - Add From Memory to Accumulator

The ADD instruction adds the value contained in the cell specified by the operand to the accumulator.

***********************************************************************
*        2:ADD - ADD FROM MEMORY TO ACCUMULATOR                       *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
@ADD     EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         LA    7,MEMTAB                      LOAD MEMORY ADDRESS
         PACK  DUBB,XOPER                    MOVE TARGET OPERAND
         CVB   3,DUBB                        CONVERT TO BINARY
         MH    3,=H'8'                       MULTIPLY BY LENGTH
         AR    7,3                           ADJUST MEMORY PTR
*
         CLI   0(7),C'-'                     NEGATIVE SIGN?
         BE    @ADDNEG                       YES - HANDLE NEGATIVE        
@ADDPOS  EQU   *
         PACK  WORK,0(3,7)                   PACK CELL VALUE
         B     @ADDACC                       ADD TO ACCUMULATOR
@ADDNEG  EQU   *
         PACK  WORK,1(2,7)                   PACK CELL VALUE
         NI    WORK+1,X'F0'                  TURN OFF SIGN BITS
         OI    WORK+1,X'0D'                  SET NEGATIVE SIGN
@ADDACC  EQU   *
         AP    XACC,WORK                     ADD TO ACCUMULATOR
*
         UNPK  XACCU,XACC                    UNPACK ACCUMULATOR
         OI    XACCU+3,X'F0'                 TURN ON ZONE BITS
         CP    XACC,=P'0'                    ACCUMULATOR NEGATIVE?
         BNL   @ADDX                         NO  - EXIT ROUTINE
         MVI   XACCU,C'-'                    SET NEGATIVE CHAR
@ADDX    EQU   *
         L     6,@ADD-4                      RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************

3: TAC - Test Accumulator - Jump If Negative

The TAC instruction performs a jump if the accumulator is negative. The program counter is set to the value of the instruction operand. Unlike the JMP instruction a return address is not formatted & placed in cell 99. This is helpful when reading input & ending with a -1 value.

***********************************************************************
*        3:TAC - TEST ACCUMULATOR - JUMP IF NEGATIVE                  *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
@TAC     EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         CP    XACC,=P'0'                    ACCUMULATOR NEGATIVE?
         BNL   @TACX                         NO  - EXIT ROUTINE
*
         ZAP   ZPC,XPC                       SAVE PRIOR INSTRUCTION
         PACK  XPC,XOPER                     SET JUMP ADDRESS
         UNPK  XPCU,XPC                      UNPACK PROGRAM COUNTER
         OI    XPCU+2,X'F0'                  TURN ON ZONE BITS
@TACX    EQU   *
         L     6,@TAC-4                      RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************

4: SFT - Shift Accumulator (Left/Right)

The SFT instruction is seldom used with very little, if any, examples in the CARDIAC documentation. The 2-digit operand is split in two and represents both a shift to the left & a shift to the right. Since we are working with 3-digit integers any shift value > 3 (in either direction) simply sets the field to zero. It's difficult to have a sensible shift with so few integers but here it is anyway. Bytes are moved in a simplistic fashion within a loop for each shift value. No need to over engineer on this one.

***********************************************************************
*        4:SFT - SHIFT ACCUMULATOR (LEFT/RIGHT)                       *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
@SFT     EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         MVI   WSIGN,C' '                    INIT NEGATIVE SIGN
         CP    XACC,=P'0'                    ACCUMULATOR NEGATIVE?
         BNL   *+8                           NO  - CONTINUE PLEASE
         MVI   WSIGN,C'-'                    YES - SET NEGATIVE SIGN
*   
         PACK  DUBB,XOPER(1)                 LOAD LEFT SHIFT VALUE
         CP    DUBB,=P'0'                    LEFT SHIFT = ZERO?
         BE    @SFTR                         YES - BYPASS LEFT SHIFT
         CP    DUBB,=P'4'                    SHIFT LESS THAN 4??
         BL    *+20                          YES - PERFORM LEFT SHIFT
         MVC   XACCU,=CL4'0000'              CLEAR ACCUMULATOR CHAR
         ZAP   XACC,=P'0'                    CLEAR ACCUMULATOR PACK
         B     @SFTX                         EXIT ROUTINE PLEASE
*
         CLI   XACCU,C'-'                    NEGATIVE SIGN?
         BNE   *+8                           NO  - CONTINUE PLEASE
         MVI   XACCU,C'0'                    YES - SET TO ZERO
*
         CVB   4,DUBB                        CONVERT SHIFT TO BINARY
@SFTLM   EQU   *
         MVC   XACCU(1),XACCU+1              SHIFT LEFT PART 1
         MVC   XACCU+1(1),XACCU+2            SHIFT LEFT PART 2
         MVC   XACCU+2(1),XACCU+3            SHIFT LEFT PART 3
         MVI   XACCU+3,C'0'                  SHIFT LEFT PART 4
         BCT   4,@SFTLM                      LOOP UNTIL COMPLETE
@SFTR    EQU   *
         PACK  DUBB,XOPER+1(1)               LOAD RIGHT SHIFT VALUE
         CP    DUBB,=P'0'                    RIGHT SHIFT = ZERO?
         BE    @SFTACC                       YES - BYPASS RIGHT SHIFT
         CP    DUBB,=P'4'                    SHIFT LESS THAN 4??
         BL    *+20                          YES - PERFORM RIGHT SHIFT
         MVC   XACCU,=CL4'0000'              CLEAR ACCUMULATOR CHAR
         ZAP   XACC,=P'0'                    CLEAR ACCUMULATOR PACK
         B     @SFTX                         EXIT ROUTINE PLEASE
*
         CLI   XACCU,C'-'                    NEGATIVE SIGN?
         BNE   *+8                           NO  - CONTINUE PLEASE
         MVI   XACCU,C'0'                    YES - SET TO ZERO
*
         CVB   4,DUBB                        CONVERT SHIFT TO BINARY
@SFTRM   EQU   *
         MVC   XACCU+3(1),XACCU+2            SHIFT RIGHT PART 1
         MVC   XACCU+2(1),XACCU+1            SHIFT RIGHT PART 2
         MVC   XACCU+1(1),XACCU              SHIFT RIGHT PART 3
         MVI   XACCU,C'0'                    SHIFT RIGHT PART 4
         BCT   4,@SFTRM                      LOOP UNTIL COMPLETE
@SFTACC  EQU   *
         PACK  XACC,XACCU                    PACK ACCUMULATOR
         CLI   WSIGN,C'-'                    ACCUMULATOR NEGATIVE?
         BNE   @SFTX                         NO  - EXIT ROUTINE PLEASE
*        
*        PRESERVE NEGATIVE SIGN (DUE TO SPACE LIMITATIONS)
*
         MVI   XACCU,C'0'                    SET HIGH ORDER TO ZERO
         PACK  XACC,XACCU                    PACK ACCUMULATOR
         NI    XACC+2,X'F0'                  TURN OFF SIGN BITS
         OI    XACC+2,X'0D'                  SET NEGATIVE SIGN
         MVI   XACCU,C'-'                    SET NEGATIVE CHAR
@SFTX    EQU   *
         L     6,@SFT-4                      RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************

5: OUT - Write Memory Location to Output

The OUT instruction writes the cell value specified by the operand to the "theoretical" printing device. In this case I have a screen variable called SCROUT that displays the output. The output values push to the right as they are written.

***********************************************************************
*        5:OUT - WRITE MEMORY LOCATION TO OUTPUT                      *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
@OUT     EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         LA    5,62                          LOAD SCROUT COUNT
         LA    6,SCROUT+61                   LOAD SCROUT OFFSET
@OUTBMP  EQU   *
         MVC   4(1,6),0(6)                   BUMP READER ENTRIES
         SH    6,=H'1'                       DECREMENT SCRRDR PTR
         BCT   5,@OUTBMP                     LOOP UNTIL COMPLETE
*
         LA    7,MEMTAB                      LOAD MEMORY ADDRESS
         PACK  DUBB,XOPER                    MOVE TARGET OPERAND
         CVB   3,DUBB                        CONVERT TO BINARY
         MH    3,=H'8'                       MULTIPLY BY LENGTH
         AR    7,3                           ADJUST MEMORY PTR
         MVC   SCROUT(3),0(7)                PRINT CELL DATA
*
         CLI   SCROUT+4,C' '                 FIRST DECK ENTRY?
         BE    *+8                           YES - BYPASS COMMA
         MVI   SCROUT+3,C','                 MOVE COMMA DELIMITER
@OUTX    EQU   *
         L     6,@OUT-4                      RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************

6: STO - Store Accumulator to Memory Location

The STO instruction places the current value of the accumulator in the cell specified by the operand.

***********************************************************************
*        6:STO - STORE ACCUMULATOR TO MEMORY LOCATION                 *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
@STO     EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         LA    7,MEMTAB                      LOAD MEMORY ADDRESS
         PACK  DUBB,XOPER                    MOVE TARGET OPERAND
         CVB   3,DUBB                        CONVERT TO BINARY
         MH    3,=H'8'                       MULTIPLY BY LENGTH
         AR    7,3                           ADJUST MEMORY PTR
         MVC   0(3,7),XACCU+1                MOVE ACCUMULATOR TO CELL
         CLI   XACCU,C'-'                    ACCUMULATOR NEGATIVE?
         BNE   @STOX                         NO  - EXIT ROUTINE
         MVI   0(7),C'-'                     YES - SET NEGATIVE SIGN
@STOX    EQU   *
         L     6,@STO-4                      RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************

7: SUB - Subtract Memory From Accumulator

The SUB instruction subtracts the value contained in the cell specified by the operand from the accumulator.

***********************************************************************
*        7:SUB - SUBTRACT MEMORY FROM ACCUMULATOR                     *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
@SUB     EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         LA    7,MEMTAB                      LOAD MEMORY ADDRESS
         PACK  DUBB,XOPER                    MOVE TARGET OPERAND
         CVB   3,DUBB                        CONVERT TO BINARY
         MH    3,=H'8'                       MULTIPLY BY LENGTH
         AR    7,3                           ADJUST MEMORY PTR
*
         CLI   0(7),C'-'                     NEGATIVE SIGN?
         BE    @SUBNEG                       YES - HANDLE NEGATIVE        
@SUBPOS  EQU   *
         PACK  WORK,0(3,7)                   PACK CELL VALUE
         B     @SUBACC                       SUB FROM ACCUMULATOR
@SUBNEG  EQU   *
         PACK  WORK,1(2,7)                   PACK CELL VALUE
         NI    WORK+1,X'F0'                  TURN OFF SIGN BITS
         OI    WORK+1,X'0D'                  SET NEGATIVE SIGN
@SUBACC  EQU   *
         SP    XACC,WORK                     SUB FROM ACCUMULATOR
*
         UNPK  XACCU,XACC                    UNPACK ACCUMULATOR
         OI    XACCU+3,X'F0'                 TURN ON ZONE BITS
         CP    XACC,=P'0'                    ACCUMULATOR NEGATIVE?
         BNL   @SUBX                         NO  - EXIT ROUTINE
         MVI   XACCU,C'-'                    SET NEGATIVE CHAR
@SUBX    EQU   *
         L     6,@SUB-4                      RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************

8: JMP - Jump & Save Program Counter

The JMP instruction performs two functions. First it takes the address of the next sequential instruction & stores it as a JMP instruction in cell 99. This means it has the prefix of "8" followed by the 2-digit cell address. This is how subroutines can be constructed. Secondly, the instruction then transfers control to the address specified by the operand - this is accomplished simply by updating the program counter.

***********************************************************************
*        8:JMP - JUMP & SAVE PROGRAM COUNTER                          *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
@JMP     EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         L     7,MEM99                       LOAD CELL 99 ADDRESS
         MVI   0(7),C'8'                     STORE JUMP OPCODE
         MVC   1(2,7),XPCU+1                 STORE PROGRAM COUNTER
*
         ZAP   ZPC,XPC                       SAVE PRIOR INSTRUCTION
         PACK  XPC,XOPER                     SET JUMP ADDRESS
         UNPK  XPCU,XPC                      UNPACK PROGRAM COUNTER
         OI    XPCU+2,X'F0'                  TURN ON ZONE BITS
@JMPX    EQU   *
         L     6,@JMP-4                      RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************

9: HRS - Halt & Reset

This stops the program & sets the program counter to the operand values of the instruction. The typical HRS code is "900" which sets the program counter to 00. In my version of the simulator I deactivate the <F1> STEP key after the halt if the 00 operand is used. At that point the user can only use <ESC> EXIT or <F4> RESET to start over.

***********************************************************************
*        9:HRS - HALT & RESET                                         *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
@HRS     EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         ZAP   ZPC,XPC                       SAVE PRIOR INSTRUCTION
         PACK  XPC,XOPER                     SET JUMP ADDRESS
         UNPK  XPCU,XPC                      UNPACK PROGRAM COUNTER
         OI    XPCU+2,X'F0'                  TURN ON ZONE BITS
@HRSX    EQU   *
         L     6,@HRS-4                      RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************

The CARDIAC Simulator and this blog topic are now complete!


That's all there is to say about that...


CARDIAC Simulation using PC/370 - Part 3

CARDIAC Simulation - Part 1 - Introduction to CARDIAC 

CARDIAC Simulation - Part 2 - Primary Logic/Architecture

CARDIAC Simulation - Part 3 - Memory Design / Management

CARDIAC Simulation - Part 4 - CARDIAC Instruction Set Processing

Welcome back! Here's the 3rd part of my CARDIAC Simulation project (See Part 1 for an Overview). As mentioned in the previous posts CARDIAC is a mini-CPU created by David Hagelbarger at Bell Labs in the 1960's. It's a theoretical piece of hardware made out of cardboard with strategically placed sliders. My daughter's college class based some assignments on it. When she showed it to me I decided to create my own working CARDIAC simulator. The question shouldn't be "Why?" - it should be "Why not?"

CARDIAC Simulator - Memory Design / Management

Above: Constructing my version of the CARDIAC Simulator. The little stick guy is trying to help...

The critical component in creating this simulator is memory design & management. Once this architecture is in place the execution of the individual instructions becomes very easy.

Memory Table - 100 Cells

The MEMTAB contains 100 entries for CARDIAC cells 00 thru 99. The first 4 positions will hold the object code & data values. Due to 24x80 screen restrictions I decided to limit the memory screen display to 3 characters. The second 2-byte position contains the numeric value of the cell (00 thru 99). The third 2-byte packed field holds the calculated displacement for the screen display. The ten's position is multiplied by 7 and the one's position is multiplied by 70. It is calculated once & used throughout the program.

*---------------------------------------------------------------------*
*        CARDIAC MEMORY/CELL LOCATIONS                                *
*---------------------------------------------------------------------*
MEMTAB   DC    100XL8'00000000F0F0000F'      MEMORY CELLS 00-99
         DC    X'FF'                         END OF TABLE
MEM99    DC    A(MEMTAB+99*8)                CELL 99 ADDRESS FOR JMP
***********************************************************************
 

Memory Initialization

Memory is initialized at the start of the program and when the <F4> RESET key is pressed. The CODE contained in the input file has already been read & stored in the table CTAB. It is distributed into the proper cells in MEMTAB in the Initialization/Reset process.

***********************************************************************
*        INITIALIZE MEMORY AREA                                       *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
INIT     EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         LA    2,BLANK                       LOAD SOURCE ADDRESS
         LA    3,1                           LOAD SOURCE LENGTH
         LA    4,MEMTAB                      LOAD TARGET ADDRESS
         LA    5,100*8                       LOAD TARGET LENGTH
         ICM   3,B'1000',BLANK               LOAD PAD CHARACTER
         MVCL  4,2                           INIT RECORD AREA
*
         LA    7,MEMTAB                      LOAD MEMORY ADDRESS
         ZAP   CTR,=P'0'                     INIT CELL COUNTER
ILOOP0   EQU   *
         CLI   0(7),X'FF'                    END OF TABLE???
         BE    ILOOP0X                       YES - EXIT LOOP
*
         OI    CTR+1,X'0F'                   TURN ON SIGN BITS
         UNPK  4(2,7),CTR                    UNPACK COUNTER
*
         PACK  WTENS,4(1,7)                  PACK TEN'S PLACE
         PACK  WONES,5(1,7)                  PACK ONE'S PLACE
         MP    WTENS,=PL2'7'                 ADJUST COL BY 7
         MP    WONES,=PL2'70'                ADJUST ROW BY 70
         ZAP   WDISP,=P'0'                   INIT DISPLACEMENT
         AP    WDISP,WONES                   ADD ROW ADJUSTMENT
         AP    WDISP,WTENS                   ADD COL ADJUSTMENT
         MVC   6(2,7),WDISP+2                SAVE DISPLACEMENT
INITBC   BC    0,INITGO
         MVC   OPRT,OBLANK                   CLEAR OUTPUT RECORD
         MVC   OPRT(7),=CL7'*MEMX*'          MOVE TRACE ID
         MVC   OPRT+7(2),4(7)                MOVE CELL NUMBER
         MVC   OPRT+11(4),0(7)               MOVE CELL CONTENTS
         UNPK  OPRT+17(3),6(2,7)             MOVE DISPLACEMENT  
         OI    OPRT+19,X'F0'                 TURN ON ZONE BITS
         XPRNT OREC,132                      WRITE OUTPUT RECORD
INITGO   EQU   *
         LA    7,8(,7)                       BUMP MEM POINTER
         AP    CTR,=P'1'                     ADD TO CELL COUNT
         B     ILOOP0                        LOOP AGAIN PLEASE    
ILOOP0X  EQU   *
         LA    8,CTAB                        LOAD CODE ADDRESS
ILOOP1   EQU   *
         CLI   0(8),X'FF'                    END OF CODE???
         BE    ILOOP1X                       YES - EXIT LOOP
*
         LA    7,MEMTAB                      LOAD MEMORY ADDRESS
         PACK  DUBB,0(2,8)                   PACK CELL NUMBER
         CVB   3,DUBB                        CONVERT TO BINARY
         MH    3,=H'8'                       MULTIPLY BY LENGTH
         AR    7,3                           ADJUST MEMORY PTR
         MVC   0(4,7),=CL4' '                CLEAR CELL CONTENTS
         MVC   0(3,7),2(8)                   MOVE CODE TO MEMORY
*
         LA    8,5(,8)                       BUMP CODE POINTER
         B     ILOOP1                        TEST NEXT ENTRY
ILOOP1X  EQU   *
         ZAP   XACC,=P'0'                    ACCUMULATOR PACKED
         MVC   XACCU,=CL4'0000'              ACCUMULATOR UNPACKED
         ZAP   ZPC,=P'-1'                    PROGRAM COUNTER PREVIOUS
         ZAP   XPC,=P'10'                    PROGRAM COUNTER PACKED
         MVC   XPCU,=CL3'010'                PROGRAM COUNTER UNPACKED
         MVC   XIR,=CL3' '                   INSTRUCTION REGISTER
         MVC   XMNE,=CL3' '                  OPERATION MNEMONIC
*
         MVC   DPTR,=A(DTAB)                 RESET DECK POINTER
         MVI   SCRRDR,C' '                   MOVE BLANK TO SCRRDR
         MVC   SCRRDR+1(L'SCRRDR-1),SCRRDR   PROPAGATE BLANKS
         MVI   SCROUT,C' '                   MOVE BLANK TO SCROUT
         MVC   SCROUT+1(L'SCROUT-1),SCROUT   PROPAGATE BLANKS
*
         OI    INITBC+1,X'F0'                DEACTIVATE TRACE OUTPUT
INITX    EQU   *
         L     6,INIT-4                      RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************
 

Displaying Memory on the Screen

As the program progresses via the <F1> STEP key the memory values may change along with the Program Counter that tracks the executable lines. An asterisk (*) is displayed on the screen to track the current instruction. The MEMTAB values are copied to the screen location using the pre-calculated displacements. The standard SCREEN build routine is then called at the top of the main processing loop.

***********************************************************************
*        MEMORY TO SCREEN                                             *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
MEMSCR   EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         LA    6,100                         LOAD CELL COUNT
         LA    7,MEMTAB                      LOAD MEMORY ADDRESS
MEMLOOP  EQU   *
         LA    5,SCRMEM0+2                   LOAD SCREEN ADDRESS
         ZAP   DUBB,6(2,7)                   LOAD DISPLACEMENT
         CVB   4,DUBB                        CONVERT TO BINARY
         AR    5,4                           ADD DISPLACEMENT
*
         CLI   0(7),C' '                     MEMORY CELL BLANK???
         BNE   MEMBC                         NO  - CONTINUE PLEASE
         MVC   0(4,5),=CL4'____'             CLEAR MEMORY AREA
         B     MEMBUMP                       BUMP CELL POINTER
MEMBC    BC    0,MEMFILL
         MVC   OPRT,OBLANK                   CLEAR OUTPUT RECORD
         MVC   OPRT(7),=CL7'*MEM#*'          MOVE TRACE ID
         MVC   OPRT+7(2),4(7)                MOVE CELL NUMBER
         MVC   OPRT+11(4),0(7)               MOVE CELL CONTENTS
         UNPK  OPRT+17(3),6(2,7)             MOVE DISPLACEMENT
         OI    OPRT+19,X'F0'                 TURN ON ZONE BITS
         XPRNT OREC,132                      WRITE OUTPUT RECORD
MEMFILL  EQU   *
         MVC   0(4,5),=CL4' '                CLEAR MEMORY AREA
         MVC   0(3,5),0(7)                   MOVE CODE TO MEMORY
         CLC   XPCU+1(2),4(7)                PROGRAM COUNTER??
         BNE   MEMBUMP                       NO  - CONTINUE PLEASE
         MVI   3(5),C'*'                     YES - FLAG CELL
MEMBUMP  EQU   *
         LA    7,8(,7)                       BUMP MEMORY ADDRESS
         BCT   6,MEMLOOP                     LOOP UNTIL COMPLETE
*
         MVC   SCRVAR+4(3),XPCU              MOVE PROGRAM COUNTER
         MVC   SCRVAR+14(4),XACCU            MOVE ACCUMULATOR
         MVC   SCRVAR+24(3),XIR              MOVE INSTRUCT REGISTER
         MVC   SCRVAR+37(3),XMNE             MOVE INSTRUCT MNEMONIC
         MVC   SCRVAR+52(2),XOPER            MOVE INSTRUCT OPERANDS
*
         OI    MEMBC+1,X'F0'                 DEACTIVATE TRACE OUTPUT
MEMSCRX  EQU   *
         L     6,MEMSCR-4                    RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************
 

CODE/DATA Loaded from Input File TDCPU.TXT

All Code & Data is contained in the file TDCPU.TXT (as opposed to entering it cell by cell like the college's online simulator). The Code & Deck entries are held in the tables CTAB & DTAB respectively. CTAB is utilized by the Memory Initialization routine while DTAB is the data source behind the INP (Read Input) CARDIAC Instruction.

***********************************************************************
*        DATA LOAD - CARDIAC CODE & DECK                              *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
DATA     EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         XFILI STDWKI                        OPEN INPUT  FILE
*
         LA    8,CTAB                        LOAD CODE ADDRESS
         LA    9,DTAB                        LOAD DECK ADDRESS
GETI     EQU   *
         XREAD IREC,80                       READ INPUT RECORD
         BNZ   EOFI                          EOF - EXIT ROUTINE
*
         CLC   IREC(5),=C'CODE:'             DATA = CODE???
         BNE   *+12                          NO  - CHECK DECK
         BAL   6,ICODE                       YES - PROCESS CODE
         B     GETI                          READ NEXT RECORD
*
         CLC   IREC(5),=C'DECK:'             DATA = DECK???
         BNE   GETI                          NO  - READ AGAIN
         BAL   6,IDECK                       YES - PROCESS DECK
         B     GETI                          READ NEXT RECORD
EOFI     EQU   *
         MVI   0(8),X'FF'                    END OF CODE TABLE
         MVI   0(9),X'FF'                    END OF DECK TABLE
DATAX    EQU   *
         L     6,DATA-4                      RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************
         EJECT
***********************************************************************
*        INPUT CODE - CARDIAC OBJECT CODE    R8=CTAB (CL2+CL3)        *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
ICODE    EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         MVC   0(2,8),IREC+5                 MOVE CELL NUMBER
         MVC   2(3,8),IREC+8                 MOVE INSTRUCTION
*
         MVC   OPRT,OBLANK                   CLEAR OUTPUT RECORD
         MVC   OPRT(7),=CL7'*CODE*'          MOVE TRACE ID
         MVC   OPRT+7(2),0(8)                MOVE CELL NUMBER
         MVC   OPRT+10(3),2(8)               MOVE INSTRUCTION
         MVC   OPRT+20(40),IREC              MOVE INPUT RECORD
         XPRNT OREC,132                      WRITE OUTPUT RECORD
*
         LA    8,5(,8)                       BUMP TABLE POINTER
ICODEX   EQU   *
         L     6,ICODE-4                     RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************
         EJECT
***********************************************************************
*        INPUT DECK - CARDIAC READER DATA    R9=DTAB (CL4+PL2)        *
***********************************************************************
         DC    F'0'                          RETURN ADDRESS SAVE AREA
IDECK    EQU   *
         ST    6,*-4                         SAVE RETURN ADDRESS
*
         MVC   0(3,9),IREC+5                 MOVE DECK VALUE
         CLI   IREC+5,C'-'                   NEGATIVE VALUE?
         BNE   *+8                           NO  - CONTINUE
         MVI   IREC+5,C'0'                   SET SIGN TO ZERO
*
         PACK  4(2,9),IREC+5(3)              PACK DECK VALUE
*
         OI    5(9),X'0F'                    SET POSITIVE SIGN
         CLI   0(9),C'-'                     NEGATIVE VALUE?
         BNE   *+12                          NO  - CONTINUE PLEASE
         NI    5(9),X'F0'                    TURN OFF SIGN BITS
         OI    5(9),X'0D'                    SET NEGATIVE SIGN
*
         MVC   OPRT,OBLANK                   CLEAR OUTPUT RECORD
         MVC   OPRT(7),=CL7'*DECK*'          MOVE TRACE ID
         MVC   OPRT+7(4),0(9)                MOVE CELL NUMBER
         MVC   OPRT+20(40),IREC              MOVE INPUT RECORD
         XPRNT OREC,132                      WRITE OUTPUT RECORD
*
         LA    9,6(,9)                       BUMP TABLE POINTER
IDECKX   EQU   *
         L     6,IDECK-4                     RESTORE LINK REGISTER
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************
 

The next post will cover the CARDIAC Instruction Set. That's where the magic happens...