{"id":70,"date":"2011-06-25T20:34:09","date_gmt":"2011-06-26T01:34:09","guid":{"rendered":"http:\/\/tommysprinkle.com\/txxos\/?p=70"},"modified":"2021-04-17T18:30:45","modified_gmt":"2021-04-17T23:30:45","slug":"80-80-list-exeuctable-code","status":"publish","type":"post","link":"https:\/\/tommysprinkle.com\/txxos\/?p=70","title":{"rendered":"80-80 List Exectable Code"},"content":{"rendered":"<p>Now we need to write our executable program.\u00a0 For now we will focus on our program and not worry about how to get it punched into 80-byte cards.<\/p>\n<p>First we need to establish a base register.\u00a0 This code is written to be relocatable so it should run from anywhere we place it in memory.\u00a0 We can move it to somewhere else other than location 1024 by modifying the PSW and the three CCWs used to read in the program.<\/p>\n<pre>BEGIN    DS    0D\r\n         BALR  R10,0                * Establish a Base Address\r\n         USING *,R10                * Tell the assembler\r\n*<\/pre>\n<p>Next we need to get the device address for the card reader\u00a0 used for the IPL process.\u00a0 This is where we will expect to find our data cards.\u00a0 When the CPU completes the IPL process and loads our initial PSW but before execution begins, the address of the IPL device is saved.\u00a0 Since we are loading a BC PSW the IPL device address is saved in locations 2 and 3.<\/p>\n<pre>         SLR   R3,R3                * Clear Register 3\r\n         ICM   R3,B'0011',2         * Load IPL Device Address\r\n         LA    R4,X'E'              * Assume Printer at 00E\r\n*<\/pre>\n<p>We will assume the printer is at device address X&#8217;00E&#8217; which is usually a standard place to define a printer.\u00a0 The standard location for the card reader is X&#8217;00C&#8217; and that for the card punch is X&#8217;00D&#8217;.<\/p>\n<p>Now we can handle some housekeeping to make our program relocatable.\u00a0 If we were running with the help of an operating system we would probably have a relocating loader.\u00a0 This means we could use an address constant (ADCON) in our CCW to point to the buffer.\u00a0 When the loader read our program into memory the value in the ADCON would be relocated or updated to reflect our actual location in memory.<\/p>\n<p>Since we are Bare Metal programming we don&#8217;t have an operating system or relocating loader.\u00a0 In fact our loader is just some CCWs that are executed by the channel at IPL.\u00a0 We will use a LA and STCM to get the actual address of the buffer at run time and store it into our CCWs.<\/p>\n<pre>         LA    R1,RDBUF          * Get the address of the I\/O Buf\r\n         STCM  R1,B'0111',RDCCW+1  Place address into Read CCW\r\n         STCM  R1,B'0111',PRCCW+1  Place address into Print CCW<\/pre>\n<p>Now we are ready to enter the main loop for our 80-80 List program.\u00a0 The first thing we want to do is attempt to read a card from the same card reader that was used as the IPL device.\u00a0 Before issuing the Start I\/O we need to place the address of our read CCW into the CAW.<\/p>\n<pre>         LA    R1,RDCCW          * Get address of Read CCW\r\n         ST    R1,72             * Place into CAW (location 72)<\/pre>\n<p>Our Read CCW should look very familiar since it is almost exactly like the CCWs used in our IPL process.\u00a0 We will not set any flags in the CCW this time.\u00a0 Since we are not command chaining our CCW program will consist of a single CCW.\u00a0 We are using command code X&#8217;02&#8217; to read, the address is filled in at run time, and we are expecting 80 bytes of data.\u00a0 This time we will leave the SLI bit off and if the card reader attempts to transfer more or less than 80 bytes an exceptional condition will occur.<\/p>\n<pre>RDCCW    DC    X'02',AL3(0),X'0000',AL2(80)<\/pre>\n<p>Now we can issue the Start I\/O instruction to cause the channel to execute our channel program.\u00a0 We have saved the address of the card reader in register three.\u00a0 We then check the condition code to see if the channel is processing our request.\u00a0 If not we load a Wait PSW and halt execution.<\/p>\n<pre>         SIO   0(R3)             * Issure Start I\/O to Channel\r\n         BNZ   ERR1              * If Chan not processing - error<\/pre>\n<p>Now we have to wait for the I\/O to complete.\u00a0 Since we have masked all I\/O interrupts the CPU will not generate an interrupt when the I\/O is complete.\u00a0 Instead we will use the Test I\/O instruction to check on the progress of the channel program.\u00a0 If the I\/O is complete we will branch out of our wait loop.\u00a0 If the return code indicates the channel or device is not operational we will load a Wait PSW.\u00a0 If the channel is still busy we will loop back and issue the Test I\/O again.<\/p>\n<pre>RDTIO    DS    0H\r\n         TIO   0(R3)             * Test for I\/O Completion\r\n         BZ    PRT               * Branch if I\/O Complete\r\n         BC    1,ERR2            * Branch if not operational\r\n         B     RDTIO             * Loop back and wait for I\/O<\/pre>\n<p>Now we need to check for successful completion of our channel program.\u00a0 We know that it completed and the completion status was stored into the CSW as a result of our issuing a Test I\/O against the device.\u00a0 We will test the status bits and we only expect to find Channel End and Device End set.\u00a0 If we find anything else some type of exceptional condition has occurred.\u00a0 We use a CLC to compare the two bytes of status bits in the CSW (located at fixed location 68) to a constant with just the Channel End and Device End bits set X&#8217;0C00&#8242;<\/p>\n<pre>PRT      DS    0H\r\n         CLC   CEDE,68           * Compare status bits\r\n         BNE   ERR0              * Branch if not CE+DE\r\n          .\r\n          .\r\nCEDE     DC    X'0C00'           * CE+DE<\/pre>\n<p>If we get anything else other than CE+DE we will save the status bits of the CCW into the address portion of a Wait PSW and then load that PSW to halt execution.\u00a0 The reason we store the status bits in the CSW is so they become the wait code (the address portion of the wait PSW) and are visible on the operator console.<\/p>\n<pre>ERR0     MVC   PSWERR0+6(2),68   * Move CSW status bits to PSW\r\n         LPSW  PSWERR0           * Load Wait PSW\r\n          .\r\n          .\r\nPSWERR0  DC    X'00',X'02',X'0000',x'00',x'000000'<\/pre>\n<p>If there is no error then we issue a Start and I\/O to the printer to print out the contents of the card we just read.\u00a0 Just as with reading a card we store the address of the CCW into the CAW and then issue the Start I\/O against the device.\u00a0 We check the condition code from the Start I\/O to verify the channel program is active.<\/p>\n<pre>         LA    R1,PRCCW          * Point to Print CCW\r\n         ST    R1,72             * Store into CAW\r\n         SIO   0(R4)             * Start I\/O on Printer\r\n         BNZ   ERR3              * Branch if Error<\/pre>\n<p>The CCW to print is similar to the CCW to read a card from the card reader.\u00a0 Each device has its own set of command codes.\u00a0 Printers have a number of command codes they respond to. Below is a quick summary of a few command codes for a printer.<\/p>\n<pre>01 - Write and Do Not Space\r\n09 - Write and Space 1 Line\r\n11 - Write and Space 2 Lines\r\n19 - Write and Space 3 Lines\r\n0B - Space 1 Line Immediate\r\n13 - Space 2 Lines Immediate\r\n1B - Space 3 Lines Immediate<\/pre>\n<p>We will use command code X&#8217;09&#8217; to write a line and then space down to the next line.<\/p>\n<pre>PRCCW\u00a0\u00a0\u00a0 DC\u00a0\u00a0\u00a0 X'09',AL3(0),X'0000',AL2(80)<\/pre>\n<p>As with the read CCW, the data address is filled in at run time.\u00a0 We will print 80 bytes of data and no flags are set.\u00a0 Our channel program will consist of a single CCW.<\/p>\n<p>Next we enter a Test I\/O loop to wait for completion of the I\/O.\u00a0 For now when the I\/O is complete we assume it was successful.\u00a0 We could check the CSW status bits for any exceptional conditions but we don&#8217;t for now to make our program smaller and simpler.<\/p>\n<pre>PRTTIO   DS    0H\r\n         TIO   0(R4)             * Wait for I\/O to Complete\r\n         BZ    RDLP              * Done - Go read next card\r\n         BC    1,ERR4            * Branch if error\r\n         B     PRTTIO            * Loop back and test again\r\n\r\n<a title=\"Creating The IPL Deck\" href=\"http:\/\/tommysprinkle.com\/txxos\/?p=94\">[Next - Creating The IPL Deck]<\/a><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Now we need to write our executable program.\u00a0 For now we will focus on our program and not worry about how to get it punched into 80-byte cards. First we need to establish a base register.\u00a0 This code is written &hellip; <a href=\"https:\/\/tommysprinkle.com\/txxos\/?p=70\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"template-page-builder-no-sidebar.php","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1],"tags":[],"class_list":["post-70","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1CPQT-18","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/tommysprinkle.com\/txxos\/index.php?rest_route=\/wp\/v2\/posts\/70","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tommysprinkle.com\/txxos\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tommysprinkle.com\/txxos\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tommysprinkle.com\/txxos\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tommysprinkle.com\/txxos\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=70"}],"version-history":[{"count":9,"href":"https:\/\/tommysprinkle.com\/txxos\/index.php?rest_route=\/wp\/v2\/posts\/70\/revisions"}],"predecessor-version":[{"id":453,"href":"https:\/\/tommysprinkle.com\/txxos\/index.php?rest_route=\/wp\/v2\/posts\/70\/revisions\/453"}],"wp:attachment":[{"href":"https:\/\/tommysprinkle.com\/txxos\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=70"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tommysprinkle.com\/txxos\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=70"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tommysprinkle.com\/txxos\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=70"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}