CHARACTER CODES IN FORTRAN VERSUS NATIVE
The IBM 1130 has disparate encodings for characters depending on the peripheral from which it comes or is written to. This eliminated the need for the device controller to convert from the native format of the device into some common lingua franca but it imposed a requirement on programmers to convert back and forth between the encodings. On the IBM 360, by comparison, each controller converts to EBCDIC thus the programmer is unconcerned with native device formats.
In Fortran, however, the programmer only deals with EBCDIC. This means that internal to Fortran run time software, every device's data is converted to and from EBCDIC. Thus, when the user pushes the Space bar on the keyboard, delivering x0000 as the value, the logic converts it to x4000 an EBCDIC space. When the user wants to print a space on the typewriter they use x4000 but it is converted to x2100 for transmission to the 1053 printer.
The consequence of this when porting is that you will find statements like:
IF (INP - IE)3,4,5
This will check the input against a constant IE which will be the EBCDIC value. When coding in Assembler, the keyboard provides Hollerith codes, so the value of IE must be converted to the Hollerith value. Again we need to convert when the code types out a character with a statement like
WRITE (TYP,1)IE
1 FORMAT(A1)
This will grab the word storing variable IE and send it to the typewriter but the Format string takes the upper 8 bits as an EBCDIC value and converts to the 1053 code before sending to the typewriter. My code has to take the value of the character for IE, but in the typewriter encoding, then put that in the first 8 bits of a word and send it to the typewriter.
There were also variables loaded with values such as:
IBLANK = 16448
IUL = 27968
IBAR = 20288
IX =-6336
These are 16 bit signed integer values that produce a word with two EBCDIC character codes. In this case, the lower eight bits is always 40 (a space) and all we care is about the upper eight bits. The four words above become x4040, x6D40, x4F40 and xE740 respectively. We turn this into x2100, xBE00, xC600 and xE700 respectively to drive the typewriter.
CONVERTING MATH FORMULAS TO 1130 ARITHMETIC INSTRUCTIONS
The statements in 1130 Fortran are represented in decimal and cover both floating point and integer data types. The 1130 hardware does not understand floating point at all, only integer. Even for programs like TicTacToe that use only integer arithmetic, one has to consider the intent of the Fortran statement and at the same time the 1130 hardware capabilities.
A statement like this in Fortran seems cumbersome:
J = I - (I/2)*2
Integer division drops any fractional part. Thus when the value 57 is divided by 2 in integer, the answer is 28 not 28.5 as would be true in a floating point calculation. When the 28 is multiplied by 2, the result is now 56. The statement above subtracts 56 from 57. If the value were 30, dividing by 2 gives 15, multiply by 2 gives 30, so that 30-30 produces 0. In other words, this expression produces a 0 if I is even and 1 if I is odd.
On the IBM 1130, the arithmetic unit has conditions that you can test in a branch instruction, one of which is EVEN. Therefore no multiplying, dividing or subtracting is needed to check whether a number is even or odd.
OLD STYLE FORTRAN SYNTAX UNFAMILIAR TO THOSE THAT KNOW MODERN FORTRAN
IBM 1130 Fortran expresses conditional statements (IF) with this syntax:
IF (value)1,2,3
This means that if the value is negative, this branches to statement 1. If the value is zero, it branches to 2. When positive, it branches to 3. One does not have statements such as IF (condition) 4 to branch to statement 4 when the condition is true, otherwise just fall through to the next statement in the program.
just for fun I coded up your 7-11 game in Python. I imagine the structure matches the shape of your assembly version.
ReplyDelete'''
7-11 game, as described by Carl Claunch who made it for the IBM 1130 demo set
'''
import random as R
STAKE = 100 # player's stake, start with $100
TOP_STAKE = 5000 # stake at which the game ends with a win
BUSTED = 0 # I don't want to allow negative stakes
MAX_BET = 1000 # largest bet (arbitrary)
MIN_BET = 1
def roll() -> tuple[int,int] :
return (R.randint(1,6),R.randint(1,6))
def get_bet() -> int:
global STAKE, MAX_BET, MIN_BET
'''
loop until valid bet received
Prompt for bet amount 1..max
validate and break if valid
return 0 to mean end
return valid bet
'''
upper_bet = min(MAX_BET,STAKE)
while True:
print()
inp = input(f"Your wager, from ${MIN_BET} to ${upper_bet} (0 to end) $")
inp = int(inp) if inp.isdecimal() else -1 # reject null or nondigit
if (inp == 0) or (inp >= MIN_BET and inp <= upper_bet):
return inp
print("Sorry, not a valid bet.")
return bet
def round(bet: int) -> int :
'''
One round of betting, returning +bet on a win, -bet on a loss
- do the first roll
- end round with loss if 2 or 12
- end round with win if 7 or 11
- note the point
- loop until some conclusion
- perform a roll on demand
- report roll
- end with win if == point
- end with loss if 7
'''
def roll_and_show() -> int :
'''
roll two dies, display, and return their sum
'''
the_dice = roll()
the_roll = sum(the_dice)
print(f"And the dice come up {the_dice[0]} and {the_dice[1]} for {the_roll}")
return the_roll
'''
First roll
'''
point = roll_and_show()
if point == 2 or point == 12 :
print("Sorry.")
return -bet
if point == 7 or point == 11 :
print("Nice one!")
return bet
while True:
print(f"Your point is {point}")
print()
the_roll = roll_and_show()
if the_roll == point :
print("Great!")
return bet
if the_roll == 7:
print("Oh, too bad.")
return -bet
def game():
global STAKE, TOP_STAKE
'''
Run the game
repeat until an end is reached:
report current stake
if stake < 0 report bust, end
if stake > TOP_STAKE, report win, end
get the bet
if bet == 0, thanks byeee
run a round, returning +/- bet
increment the stake by bet
'''
while True:
print(f"Your present stake: ${STAKE}")
if STAKE <= BUSTED :
print("Sorry, you're busted.")
return
if STAKE > TOP_STAKE :
print("And that's a win, cash out and go have a drink!")
return
bet = get_bet()
if bet == 0 : # user wants to quit
return
STAKE += round(bet)
if __name__ == "__main__" :
game()
It required 350 lines of assembler, but also leveraged routines in the demo monitor which together comprise about another 375 lines. Sadly no Python back in the day.
ReplyDelete