Skip to content

Instantly share code, notes, and snippets.

@sanzaru
Last active June 2, 2020 10:27
Show Gist options
  • Save sanzaru/0b50599be7ba9e88439cb77365110a47 to your computer and use it in GitHub Desktop.
Save sanzaru/0b50599be7ba9e88439cb77365110a47 to your computer and use it in GitHub Desktop.
Simple program to encode ASCII punch card files for the IBM 1401 into binary (BCD) the machine understands.
/**
* This is a simple program to encode ASCII punch card files for the IBM 1401
* into binary the machine understands.
*
* The IBM 1401 was build before ASCII was invented, so it used its own binary
* encoding for characters. This program will encode all ASCII into
* corresponding 1401 encoding.
*
* Usage: node ibm1401-bc.js <file>
*
* The file should be a plain ASCII file containing the punch card code, e.g.:
*
* ,0080015,022029,M077211
*
* -----------------------------------------------------------------------------
*
* Copyright (c) 2020 Martin Albrecht <martin.albrecht@seriousmonkey.de>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
const fs = require('fs')
// BCD character encodings
// Bit positions are: WM | C | B | A | 8 | 4 | 2 | 1
const CharacterEncodings = {
// Default SimH encoding
default: {
'A': 0b00110001, 'B': 0b00110010, 'C': 0b01110011, 'D': 0b00110100,
'E': 0b01110101, 'F': 0b01110110, 'G': 0b00110111, 'H': 0b00111000,
'I': 0b01111001, '&': 0b01110000, '.': 0b00111011, ')': 0b01111100,
'J': 0b01100001, 'K': 0b01100010, 'L': 0b00100011, 'M': 0b01100100,
'N': 0b00100101, 'O': 0b00100110, 'P': 0b01100111, 'Q': 0b01101000,
'R': 0b00101001, '-': 0b00100000, '$': 0b01101011, '*': 0b00101100,
'/': 0b01010001, 'S': 0b01010010, 'T': 0b00010011, 'U': 0b01010100,
'V': 0b00010101, 'W': 0b00010110, 'X': 0b01010111, 'Y': 0b01011000,
'Z': 0b00011001, '\'': 0b00011010, ',': 0b01011011, '%': 0b00011100,
'#': 0b00001011, '@': 0b01001100, '0': 0b01001010, '1': 0b00000001,
'2': 0b00000010, '3': 0b01000011, '4': 0b00000100, '5': 0b01000101,
'6': 0b01000110, '7': 0b00000111, '8': 0b00001000, '9': 0b01001001,
' ': 0b01000000, ':': 0b00001101, '>': 0b00001110, '(': 0b01001111,
'^': 0b00010000, '\\': 0b01011110, '+': 0b00011111, '!': 0b00101010,
']': 0b01101101, ';': 0b01101110, '_': 0b00101111, '?': 0b01111010,
'[': 0b00111101, '<': 0b00111110, '"': 0b01111111
},
}
var assembly = (buffer, encoding, filename) => {
if (buffer && encoding && filename) {
let binaryData = Buffer.alloc(buffer.length)
// Iterate over characters
for (let c = 0, len = buffer.length; c < len; c++) {
if (buffer[c] && buffer[c] !== '\n') {
if (CharacterEncodings[encoding].hasOwnProperty(buffer[c])) {
binaryData[c] = CharacterEncodings[encoding][buffer[c]]
} else {
const err = `Aborting on unknown character: ` +
`${buffer[c]} at index ${c}\n` +
`Dec: ${c.toString(10)}` +
` | Hex: ${c.toString(16)}` +
` | Bin: ${c.toString(2)}\n`
throw new Error(err)
}
}
}
console.log(`\nWRITING FILE:\t${filename}.bc\nLENGTH:\t\t${binaryData.length} bytes`)
fs.writeFileSync(`${filename}.bc`, binaryData, 'binary')
}
}
var disassembly = (buffer, encoding, filename) => {
let asciiData = ''
if (buffer && encoding && filename) {
for (let c = 0, len = buffer.length; c < len; c++) {
if (buffer[c] && buffer[c] !== '\n') {
for (let item in CharacterEncodings[encoding]) {
if (CharacterEncodings[encoding].hasOwnProperty(item)) {
if (CharacterEncodings[encoding][item] == buffer[c]) {
asciiData += item
break
}
}
}
}
}
}
console.log(`\nWRITING FILE:\t${filename}.dis\nLENGTH:\t\t${asciiData.length} bytes`)
fs.writeFileSync(`${filename}.dis`, asciiData)
}
var usage = () => {
throw (`Usage: .${__filename} [-d] -f <file>`)
}
try {
// Parse command line arguments
const argv = process.argv
if (argv.length < 3) {
usage()
}
// Fetch file name and extension
let index = argv.indexOf('-f')
if (index === -1) {
usage()
}
const filename = argv[index + 1].trim().split('.')
const extension = filename.splice(-1)
if (!filename || !extension) {
throw (`Error: Invalid filename. Should be of scheme: FILENAME.EXT, but is: ${argv[index + 1]}`)
}
const disassemble = argv.indexOf('-d') !== -1
// Set encoding for BCD to ASCII conversion
const encoding = 'default'
// Intro banner
//console.clear()
console.log('=========== IBM 1401 BINARY ENCODER ===========\n')
console.log(`READING FILE:\t${filename}\nEXTENSION:\t.${extension}`)
console.log(`ENCODING:\t${encoding}`)
console.log(`MODE:\t\t${disassemble ? 'Disassemble' : 'Assemble'}`)
// Read in data
const buffer = fs.readFileSync(argv[index + 1])
if (buffer) {
if (disassemble) {
disassembly(buffer, encoding, filename)
} else {
assembly(String(buffer).trim().toUpperCase(), encoding, filename)
}
}
console.log('DONE\n')
} catch (e) {
console.error(e)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment