IBM 1401  

  RSS

triform
(@triform)
Estimable Member
Joined: 5 months ago
Posts: 194
2019-10-09 5:40 pm  

I have not been reading the forums as late, and I just saw a post mentioned one of my favorite computers, the IBM 1401!

As an office-chair computer historian, I love reading and learning about older computers that pre-date my time as a computer scientist. The 1401 is a fascinating computer, with a very different architecture than modern computers.  The way it handled numbers and math was neat (I think so anyway). 

Anyway, last year I started an emulator project for the 1401 in C as a weekend project, that I plan working on again this winter.  The code is probably about 65% finished.  I also will be porting an assembler to it that I am currently working on for a nother project. 

I would love to make a fake one with hardware/software, but probably will forgo that part 🙂

@joelyddon will probably remember this book:

IMG 20191009 121222

 

I also have this one:

IMG 20191009 122940

 


Quote
JoeLyddon
(@joelyddon)
Estimable Member
Joined: 3 months ago
Posts: 101
2019-10-09 6:47 pm  
Posted by: @triform

I have not been reading the forums as late, and I just saw a post mentioned one of my favorite computers, the IBM 1401!

As an office-chair computer historian, I love reading and learning about older computers that pre-date my time as a computer scientist. The 1401 is a fascinating computer, with a very different architecture than modern computers.  The way it handled numbers and math was neat (I think so anyway). 

Anyway, last year I started an emulator project for the 1401 in C as a weekend project, that I plan working on again this winter.  The code is probably about 65% finished.  I also will be porting an assembler to it that I am currently working on for a nother project. 

I would love to make a fake one with hardware/software, but probably will forgo that part 🙂

@joelyddon will probably remember this book:

IMG 20191009 121222

 

I also have this one:

IMG 20191009 122940

 

Fantastic!   I agree with you 200%.

For example, how many computers, of today, can solve and printout the result of 99 to the 99th power?  Not just a few significant numbers & the rest left to just decimal point adjustments...  Every single NUMBER from start to finish!

The 1401, with it's variable word length, could do it...  and, in fact DID IT by a fellow programmer I was working with at the time!...   It took several PAGES of nothing but numbers 132 char. lines  14x11 paper...!!   I wish I had filed it away and kept it...  but, it got lost along the way!

When the 2311 & 2314 disk drives hit the scenes... soon after, I developed a way to store object programs on disk, wrote a high memory resident Disk Program loader and executed them as if they loaded from cards!   I did this BEFORE the 360 was present, which did this very same thing.   I had trays of job-stream Object Programs loaded onto disk and executed just using a 1/2" worth of Job Control cards!   Card data input would be placed in their required places for program execution.  It was awesome!  Saved a lot of execution time and was so much easier to execute, removing ALL OF THAT CARD HANDLING!  I basically wrote a small DOS for the 1401!!

The loader in the Object decks instead of using the "1040" etc. to load & "Read and branch to 40", the records would be read from disk (disk program in high memory & was protected...  system house RULE)...  Instead of reading cards, the high memory program would read the next disk record, load, and branch back to the high memory disk to read the next program record.   Handled overlay subroutines, etc. NO SWEAT...  was truly a major breakthrough in the ease of processing huge amounts of Job Stream programs.

 

Later, when the 360 came along, we used the 1401 Emulator...  and this very system worked good on the 360 in 1401 mode too!  It was fantastic!

I hope you have FUN working on your project...   I would like to know HOW you are going to handle huge calculations like 99 to the 99th Power.  That is a HUGE Word length to emulate!   Please let me know if your project will do that calculation...  I can't see how you can do it, right off...  Current day computers just cannot possibly handle such large numbers...  The largest Floating Point # can't come close to it.

Thank you for keeping me updated on your progress...  Sounds very interesting!

Later...  & Good Luck!

(Sorry for the long-winded response...  but, you really hit my GO BUTTON!  🙂  )

 

 

Have Fun,
Joe Lyddon

www.woodworkstuff.net


ReplyQuote
JoeLyddon
(@joelyddon)
Estimable Member
Joined: 3 months ago
Posts: 101
2019-10-09 6:56 pm  

... and that's when we had, at the most, 16K of actual CORE Memory!  (not even a MB!)...  If our computers had 1 MB of memory, we were in HOG HEAVEN...  and if we had 3 MB of memory, it was REAL HEAVEN!

Of course, we did not have special Fonts and Pictures / Graphics either...  Just text & numbers!

... we had to be very concise with our coding to SAVE as much memory as possible...

Like:

"Print

CS

CS"  would print and Clear storage from 132-100 with only 3 bytes!

 

 

This post was modified 2 months ago by JoeLyddon

Have Fun,
Joe Lyddon

www.woodworkstuff.net


ReplyQuote
triform
(@triform)
Estimable Member
Joined: 5 months ago
Posts: 194
2019-10-09 7:24 pm  

@joelyddon

No problem, I love talking about the 1401 and it's even better you used it in the correct time context!  I would have loved to see your DOS-like code!

For maths, I will be emulating the 1401 just the way it did it, one number at a time until a word-mark is reached. 

This is one of the last things I wrote in the code, but here is my add and sub, not fully tested yet! Think of this as thinking out loud in code 🙂

int do_add (void)
{
     char a_address[6], b_address[6], real_addy[7];
     int a_addy = 0, b_addy = 0, adding = 1;
     char a_num = 0, b_num = 0, sum_of = 0, carry = 0, a_self_add = 0;
     int a_wm_addy = 0, b_wm_addy = 0;

     printf ("->%s<-\n", _1401_Ins_Code_Set);

     if (_1401_Ins_Code_Set[1] != 0) {
         strncpy (a_address, _1401_Ins_Code_Set + 1, 3);
         xlat_address (a_address, real_addy);
         a_addy = atoi(real_addy);

         if (_1401_Ins_Code_Set[4] != 0)
         {
            strncpy (b_address, _1401_Ins_Code_Set + 4, 3);
            xlat_address (b_address, real_addy);
            b_addy = atoi(real_addy);
         } else {
            // Add A to itself. 
            a_self_add = 1;
            b_addy = a_addy;
         }
     } else {
         // Chain call so use current A and B pointers.
         a_addy = atoi(_1401_A_Reg);
         b_addy = atoi(_1401_B_Reg);         
     }

     while (adding) {
        if (_1401_mem[a_addy].word_mark == 1 || _1401_mem[b_addy].word_mark == 1) {
           adding = 0;
        }

        // Do a check for WM on A and B.
        a_num = _1401_mem[a_addy--].mem_char - 48;
        b_num = _1401_mem[b_addy].mem_char - 48;
        sum_of = a_num + b_num + carry;
        if (sum_of > 9) {
           carry = 1;
           sum_of -= 10; 
        } else {
           carry = 0;
        }

        // Result goes back in b address
        _1401_mem[b_addy--].mem_char = (sum_of + 48);

        // Do check for memory underflow.
        if (a_addy < 1 || b_addy < 1) {
           printf ("a_addy = <%d>, b_addy = <%d>\n\n", a_addy, b_addy);
           panic ("Add caused adress under flow");
        }
     }

     if (carry == 1) {
        _1401_mem[b_addy].mem_char = _1401_mem[b_addy--].mem_char + 1;
     }

     // Preserve for possable chaining.
     sprintf (_1401_A_Reg, "%d", a_addy);

     // Only save B if it was not an A self add.
     if (a_self_add == 0)
        sprintf (_1401_B_Reg, "%d", b_addy);

     return 0;
}

int do_subtract (void)
{
     char a_address[6], b_address[6], sign = 'P';
     int a_addy = 0, b_addy = 0, subtracting = 1;
     char real_addy[7], a_num = 0, b_num = 0, diff_of = 0, borrow = 0;
     int a_wm_addy = 0, b_wm_addy = 0;

     printf ("->%s<-\n", _1401_Ins_Code_Set);

     if (_1401_Ins_Code_Set[1] != 0) {
         strncpy (a_address, _1401_Ins_Code_Set + 1, 3);
         xlat_address (a_address, real_addy);
         a_addy = atoi(real_addy);

         if (_1401_Ins_Code_Set[4] != 0)
         {
            strncpy (b_address, _1401_Ins_Code_Set + 4, 3);
            xlat_address (b_address, real_addy);
            b_addy = atoi(real_addy);
         }
     } else {
         // Chain call so use current A and B pointers.
         a_addy = atoi(_1401_A_Reg);
         b_addy = atoi(_1401_B_Reg);         
     }

     while (subtracting) {
        if (_1401_mem[a_addy].word_mark == 1 || _1401_mem[b_addy].word_mark == 1) {
           subtracting = 0;
        }
        
        // Do a check for WM on A and B.
        a_num = _1401_mem[a_addy--].mem_char - 48;
        b_num = _1401_mem[b_addy].mem_char - 48;

        // See if a borrow or nex is needed.
        if (b_num < a_num) {
           if (_1401_mem[b_addy].word_mark == 1) {
              sign = 'N';
           } else {
              _1401_mem[b_addy-1].mem_char--;
              b_num++;
              sign = 'P';
           }
        }

        diff_of = b_num - a_num;

        // Result goes back in b address
        _1401_mem[b_addy].mem_char = (diff_of + 48);
        _1401_mem[b_addy--].sign = sign;

        // Do check for memory underflow.
        if (a_addy < 1 || b_addy < 1) {
           printf ("a_addy = <%d>, b_addy = <%d>\n\n", a_addy, b_addy);
           panic ("Subtract caused adress under flow");
        }
     }

     // Preserve for possable chaining.
     sprintf (_1401_A_Reg, "%d", a_addy);
     sprintf (_1401_B_Reg, "%d", b_addy);

     return 0;
}

ReplyQuote
triform
(@triform)
Estimable Member
Joined: 5 months ago
Posts: 194
2019-10-09 7:53 pm  

@joelyddon

It looks like the 360 1401 emulator is still being maintained! 😉 

https://github.com/moshix/IBM1401

 


ReplyQuote
JoeLyddon
(@joelyddon)
Estimable Member
Joined: 3 months ago
Posts: 101
2019-10-09 8:11 pm  

@triform

Looks good...  I'm NOT proficient in C++ at all (I presume this is C++)...

It gives me something to study & hopefully learn more about C++.

If I remember, I think that Multiply & Divide functions were done with only ADD and Subtract functions...  So, it looks like you're are on the correct path!

I will study your program & hopefully learn something by osmosis...  🙂

Thank you!

 

 

Have Fun,
Joe Lyddon

www.woodworkstuff.net


ReplyQuote
JoeLyddon
(@joelyddon)
Estimable Member
Joined: 3 months ago
Posts: 101
2019-10-09 8:14 pm  
Posted by: @triform

@joelyddon

It looks like the 360 1401 emulator is still being maintained! 😉 

https://github.com/moshix/IBM1401

 

WOW!

That is very surprising!!  Some good ole dogs never die!  🙂  😀

 

Have Fun,
Joe Lyddon

www.woodworkstuff.net


ReplyQuote
triform
(@triform)
Estimable Member
Joined: 5 months ago
Posts: 194
2019-10-09 8:25 pm  
Posted by: @joelyddon

@triform

Looks good...  I'm NOT proficient in C++ at all (I presume this is C++)...

It gives me something to study & hopefully learn more about C++.

If I remember, I think that Multiply & Divide functions were done with only ADD and Subtract functions...  So, it looks like you're are on the correct path!

I will study your program & hopefully learn something by osmosis...  🙂

Thank you!

 

 

It's strait old C. I'm not a fan of C++, but at its core it's C.

As far as I can tell, Mul and Div were just that.

This post was modified 2 months ago by triform

ReplyQuote

Please Login or Register