• Please review our updated Terms and Rules here

Programming environment, ca. 1983

pseudocode

New Member
Joined
Apr 26, 2021
Messages
2
Recently, the PCJam came into my field of vision, and I thought that approaching this in a "simulationist" way would be an interesting approach and get me away from the option paralysis of my more contemporary programming work and hobbies (way too many programming languages these days...).

The game jam suggests Open Watcom and other more contemporary tools, but I thought about doing it as if I "were there", using the tools that would've been available for someone back then. As the game jam only targets CGA, I thought that this would mean that I couldn't get my hands on anything more modern. As the EGA came out in late 1984, that would be my "soft" deadline for the availability of compilers/assemblers. Could add 1-3 years, by pretending my time-slipped alter ego just couldn't afford anything more modern.

I'm probably not switching to actual '83 hardware (DOSBox instead) and art would be done with more modern tools or by simply copying free assets -- let's assume that's done by a more artistic friend back in '83. Probably going to make a simple, Ultima-ish RPG.

(For reference, my real-timeline start was Borland C++ 3.1, with only a tiny bit of C64 Basic before that. Did some assembly back then, and some Pascal/Oberon in the mean time. Current professional languages are mostly Java, Perl, JavaScript; no problem learning something new)

So where would this put me?

Given the resources, assembly would probably play a role. So MASM 1.x? Not sure whether I'd want to do the whole game this way, but it would be an option.

Turbo Pascal 1.0 came out in '83, so this might be an option. Also legally available for free, so I wouldn't need to hunt ebay for compilers.

I only heard bad things about early Microsoft C compilers. Turbo C 2 would be out of the time frame, but bearably so.

I'd be willing to try other languages, too, if the tooling would be worth it.

If it's an early compiler, I'd probably also need an extra editor. I don't really want to do edlin, so I might need to "time travel" for that or just do it with some semi-appropriate modern editor externally (JOE with its WordStar mode seems okay, or micro-emacs).
 
It's not a simple picture.

Microsoft C wasn't awful--I still use it for 16-bit code on occasion. But the environment for programming in 1983 wasn't too different from that, in say, 1975. Text editor, compiler/assembler. In 83, although I did some C work, on DOS, it was almost all assembly. But that depends on your system and area of specialization. In 1977, while I worked in assembly, the people on the other side of the building worked exclusively in a dialect of BASIC. Mainframe programmers were even more diverse.

I did have a co-worker who preferred to do most of his "quick an dirty" stuff in PL/M. The pretty much run-anywhere language then was FORTRAN. If you had a machine with a FORTRAN compiler, regardless of operating system or lack thereof, you could run FORTRAN portably. Observe that in the later CP/M-80 days, DRI was really pushing PL/I for its ISV program. The Unix people were pretty much C-exclusive.
 
Turbo Pascal 1.0 may not be up to the task. It's a great system, but doesn't have the flexibility of things like the C compilers, notably because you don't have the link step to help assemble your final executable. I don't even think TP 1.0 made EXEs, just COM files.

However, your development cycle will certainly be exaggerated by not using TP. That all depends on your hardware, however. 1983 was pretty early in the PC era with lots of things being straight up ports from CP/M and all of those limitations.

You will have an easier time mixing/matching C and ASM than I think TP and ASM.
 
This is a most fascinating subject!

Back in 1983 (depending on what month of 1983) you had a few options to program for the IBM PC and compatibles. In my opinion, and in my observations, almost all the games published commercially between 1981 and somewhere in 1984 (they could had been developed in 1983 but released in '84) were written in assembly language, specifically the Microsoft Macro Assembler 1.0.

The high level options available back then had no specific video game library options (actually there wasn't any video game specific library for PC until many, many years after), specially regarding sprite animation, so games were mostly programmed directly on assembly, as direct access to memory and the iron was a requirement if the game had a minimum level of complexity. The graphic libraries available at that time (like GWBASIC's or Turbo Pascal's) were quite limited, business oriented and slow. Another very important factor is that we are not yet in 1988, so they are very few computers that have more than 256 kb of memory: no computer is sold at that time with 512 or 640kb of memory, the memory expansions are expensive... and there's little to none software yet able to take advantage of it. So games are planned to run on very tight systems, having 64-128 kb of ram on average for greater compatibility.

The processor is also the ubiquitous 8088 at 4.77 Mhz. It's still one year to see the born of the AT (286, much faster processor, but it also will be much, much more expensive) or the Compaq Deskpro (8086 instead 8088, which is slightly faster, and 7.16 Mhz of speed). Nevertheless, the reign of the 4.77 Mhz is far to its end yet. High level languages, specially Basic and C, bloat spectacularly the generated code, and the resulting machine code is generally much slower that an intelligently programmed assembly code. So even when most of high level languages are able to interface with the assembler or insert directly machine op codes, I think it was generally an option to avoid at that moment, as a C program could quickly deplete the little RAM available. A few years after, when most systems will have 512-640 kb of memory, things will start slowly to change. But for this moment in 1983, many games use a single .com or .exe executable that includes in just one 64kb segment both code and data, and in the data were included the graphics and beeper noises/melodies.

I'm thinking, among others, in PC-MAN, Paratroopers, Burger Time (1982) and Digger, Space Invaders (1983).

So, what options can we have to program a game like it is 1983? The ones that come to my mind are:

- IBM Personal Editor. An absolute classic, available since 1981. For editing any kind of text file, including assembly, C or whatever.

- MASM 1.0 (the above mentioned Microsoft Macroassembler). Indispensable for any high performace-low memory consuming game.

- Turbo Pascal 1.0 (also above mentioned). This was revolutionary at that time as it was one of the first (maybe the first for PC?) integrated programming environments. On the same program you edited the code and also run or compile. For the first time it wasn't needed to have a separate text editor and a command line compiler+linker. This would speed the development process. Also the programming language was a "serious" structured and powerful one: the Pascal, with its pointer/memory management, plus a few PC and DOS specific functions. It has a quite complete graphic library (but nothing to manage sprites animation, scroll and the like). It also had the option to insert machine op codes (no inline assembly or .OBJ interface yet). Until version 4.0, it generates .com files, therefore restricted to 64 kb code+data.

- GWBASIC/BASICA + BASCOM (IBM Basic Compiler 1.0). GWBASIC could be used as a quick develop environment with instant result testing. The program finally could be saved on text format (save "program.bas",a) for being compiled with the BASCOM. GWBASIC has commands to send/read data to/from the ports and can load/call/execute external compiled/assembled code.It also has many primitives to draw graphics on the CGA. In fact, games such as DONKEY.BAS (one of Bill Gates gifts to humanity :mrgreen:) were made in BASIC. On the Michael Abrash book Graphics for the IBM PC, published in 1984, there are lots of examples of graphic programming of the CGA in BASIC, including a quite good brick breaking game. The worse thing is that the numbered approach and the lack of real structure keywords make this language very prone to make spaghetti code, very difficult to maintain of expand. This is my least favorite approach.

- Latice C (bought and rebranded soon by Microsoft, who back then still hadn't finished its own C compiler). I have not many information about this. I assume it can generate OBJ files and it can call assembled procedures but I'd had to check it to be sure.

- Desmet C. The earliest version I was able to find on the Internet is 2.51, from 1985. It's possible that earlier versions existed back in 1983. The 1985 version has inline assembly and can communicate with assembled procedures produced by it's close cousin, the A88 assembler (with a slightly different syntax to MASM).

So, if you are planning to make an RPG game, and there will not be an extensive use of graphic animations, you could use your favorite language and use the graphic primitives to draw lines or whatever and simple procedures to load and show static images. If you plan to offer a good deal of animations (as it would be on an arcade type game), I think a lot of assembly would be required, either standalone or supporting the high level language you chose.

Regarding the developing system, you can use DosBox (I certainly use it too) but in order to test the programs on a like '83 environment, you should lower the cycles to something between 260 and 280 to simulate a 4.77 machine. For later machines, ~550-650 could be more or less an 8086-8 Mhz machine. 800-1200 could be an AT. This is all very approximate. I give these numbers as a reference only and in the wish someone could find them useful.

For something even closer to the real thing, I would use 86Box, configuring a few virtual machines of the time (IBM PC 1982, IBM XT 1982, Compaq Portable).
 
UCSD Pascal has sound support for the speaker within the IBMSPECIAL unit. UCSD Pascal also supports graphic modes and color. Just a choice if you want to try writing code with an IDE available before Turbo Pascal.

Forth would have been around with a number of implementations for the IBM PC in 1983.
 
MASM 1.0 was probably one of the buggiest assemblers I used, bar none. The list of errata that followed it was almost 2 pages long. $99 at the time. It was a bit of a letdown after years of using Microsoft M80, which was really a decent product for the x80 CPUs

Actually, MASM 1.0 was two assemblers: ASM, non-macro and MASM, the macro assembler. I don't think that Microsoft or IBM used it for production work initially. Still, like farming in a minefield, it can be useful, as long as you knew where the mines were buried.

Lattice C was the official compiler recommended by Microsoft. It was okay, came on two floppies and was more-or-less straight K&R dialect. It's as close to C90 as a lawnmower is to a pickup truck.

As far as text editors, I'm not aware of anyone who actually put up with EDLIN for very long. There were many better ones. EDLIN was actually less powerful than CP/M ED.
 
UCSD Pascal has sound support for the speaker within the IBMSPECIAL unit. UCSD Pascal also supports graphic modes and color. Just a choice if you want to try writing code with an IDE available before Turbo Pascal.

Frankly, UCSD is one of the most powerful system available at the time, especially for large programs.

Specifically, UCSD had very good support for segments and overlays, even in the early versions of the system. Of course, you can always ad hoc your own overlay system in assembly and C, but UCSDs was "free" and automatic, you just had to be conscientious in using it.

For a stand alone "boot from floppy" system, this could work fine. But not for something that runs from DOS, as UCSD at the time was it's own OS.

As for Forth, no doubt there were several available, could always port a FIG source.

But if you want to be pedantic, you won't have access to F83 (a public domain implementation of Forth-83), one of the best from the era, and is really quite nice (it's a huge system), but likely just outside of your time window. If you're willing to bend a little, it's really powerful if you can wrap your head around it.
 
To the OP: Pretty much all games made in the first two years of the IBM PC's life were done in either assembler or BASIC, so that should answer your question. If assembler is too difficult to learn in the short term, I'd suggest you start reading any number of IBM PC BASIC books (there were nearly a hundred).

While UCSD Pascal was available for the PC in 1982, the only game I know of that used it was Wizardry which was released for the PC in April 1984.
 
I think in 1983, quite a number of firms didn't do software development on IBM PC-based systems. For example, Sorcim (Pascal-M, SuperCalc, SuperWriter, SuperProject, etc.) did most of their work on a VAX 11/730 or CompuPro 8086 boxes. I suspect that the BIOS listing in the 5150 techref was made with a cross-compiler.
 
'President's Choice' ('84) was also UCSD Pascal. Possibly a different version of it, because the code it produced is full of "mov cs,ax" instructions (undocumented, and won't work on >8088 CPUs).

Some of the Spinnaker games were written in MVP-FORTH (Facemaker, Story Machine; 1982-3?), and those "101" trivia games published by IBM were in a different FORTH dialect. The whole "threaded code" thing sure makes for an interesting experience when you have to use a debugger...

Digger (1983) was written in Lattice C, and in fact the sources are available at digger.org.

As for BASIC, it was not at all uncommon to include machine language routines in BASICA/GW-BASIC programs (interpreted or compiled) to get around the limitations of the language. Not that the interface is convenient or fun in any way, but that's what people had to contend with. ;)
 
Last edited:
Digger (1983) was written in Lattice C, and in fact the sources are available at digger.org.

Wow! I didn't know it. Thanks for the info :D Just downloaded and studying it now...

For the OP, I'm posting here the brick game by Abrash written for BASIC, if it serves as inspiration.

Code:
10 REM Blockbuster - finished version.
100 DEFINT A-Z:SCREEN 1,0:COLOR 0,1:KEY OFF:CLS
110 CIRCLE(3,3),2,3:PAINT STEP(0,0),3
120 DIM BALL(10):GET(0,0)-(5,5),BALL
130 LINE(0,0)-(319,199),2,BF:LINE(80,20)-(241,185),0,BF
140 FOR I=0 TO 7:FOR J=0 TO 3:LINE(82+20*I,48+J*12)-STEP(18,8),((I-KJ) MOD 2)+L,BF:NEXT J:NEXT I
150 NBALLS=3:NBRKS=32
160 PX=150:PXINC=0
170 LOCATE 2,2:PRINT "Balls left ";NBALLS:IF NBALLS=0 THEN LOCATE 15,13:PRINT "YOU LOST!!!!":GOTO 300
180 BX=80:BY=100:BXINC=4:BYINC=4:PUT(BX,BY),BALL
190 A$=INKEY$:IF A$="c" THEN PXINC=5 ELSE IF A$="z" THEN PXINC=-5 ELSE IF A$="x" THEN PXINC=0
200 OLDPX=PX:PX=PX+PXINC:IF PX<80 OR PX>221 THEN PX=OLDPX
210 LINE(OLDPX,181)-(OLDPX+20,181),0:LINE(PX,181)-(PX+20,181),3:OLDPX=PX
220 OLDBX=BX:BX=BX+BXINC:IF BX<80 OR BX>234 THEN BXINC=-BXINC:BX=BX+2*BXINC
230 OLDBY=BY:BY=BY+BYINC:IF BY<24 THEN BYINC=-BYINC: BY=BY+2*BYINC
240 IF BY>175 THEN IF BX<PX-5 OR BX>PX+20 THEN 280 ELSE BYINC=-BYINC:BY=BY+2*BYINC:BXINC=(BX-PX) \2-4
250 PUT(OLDBX,OLDBY),BALL:IF POINT(BX+2,BY+2)=0 THEN GOTO 260 ELSE PAINT(BX+2,BY+2),0:BYINC=-BYINC:BY=BY+2*BYINC:NBRKS=NBRKS-1:LOCATE 2,20:PRINT "Bricks left";NBRKS:IF NBRKS=0 THEN LOCATE 15,13:PRINT "YOU WON!!!!": GOTO 300
260 PUT(BX,BY),BALL
270 GOTO 190
280 NBALLS=NBALLS-1
290 PUT(OLDBX,OLDBY),BALL:GOTO 170
300 LOCATE 25,9:PRINT "PRESS ANY KEY TO CONTINUE";
310 A$=INKEY$:IF A$="" THEN 310 ELSE CLS
320 END

The book Graphics for the IBM PC can be read/downloaded here

I would like to point that while the highest performance graphics (and a few advanced things like masking the sprites in order to preserve the background) I think they would require assembly, some more BASIC graphic things (pun intended :)) can be done directly on high level, either using the language graphic primitives or using some custom ones. The following example is taken from François Gervais book Programmation des cartes CGA,EGA,VGA, published in 1988 or maybe '89. It's written originally for Turbo Pascal 3.0 or higher but I just checked that it works also on TP 1.0. It doesn't use assembly or op codes at all:

Code:
TYPE
screen_ptr = ^type_screen;
type_screen= ARRAY[0..16383] of BYTE;

VAR
screen: type_screen ABSOLUTE $B800:0;
i : BYTE;
picture_ptr,
virtual_screen: screen_ptr;

PROCEDURE show_sprite(x,y,number : BYTE);

TYPE
picture = ARRAY[0..7] of BYTE;

CONST
height : picture = (13,14,11,10,10,08,10,19);
width : picture = (20,20,23,25,23,25,26,30);

VAR
line : BYTE;

BEGIN
FOR line:= 0 TO height[number] DO
BEGIN
MOVE(picture_ptr^[80*(25*(number DIV 2)+line)+40*(number MOD 2)],
virtual_screen^[80*(y+line)+x],width[number]);
MOVE(picture_ptr^[80*(25*(number DIV 2)+linea)+8192+40*(number MOD 2)],
virtual_screen^[80*(y+line)+x+8192],width[number]);
END;
END;

(I've translated the variable names into English and the example is not complete, it lacks, for example, the mode 4 initialization code).

It doesn't preserve the background nor can put the sprite on any horizontal position of the screen (only multiples of 4) but it can be useful anyway. An assembly equivalent would be faster but the performance is not that bad.
 
Last edited:
Thanks for all the answers. It's funny that Michael Abrash appears here, too, as my own DOS/C/ASM appearance a decade later was quite heavily based on his ModeX stuff and later books...

I've also been reading some 'PC Mag' issues from archive.org, and that's been both fun and enlightening. Apparently "many users feel that APL is the most advanced general purpose programming language available today". A review of some Pascal compilers included one I actually knew (Pascal/MT+). BASIC is used for handy tips to the readers, peeking and poking to fix and detect issues.

But that's also quite exciting. I've got more room to breathe than some 8 bit home computers, but a different enough software and graphics situation to create some good constraints for the design.

I do have to make sure that "different" doesn't make it too complicated, finishing the project is more important than fiddling around with optimization. Which also means, that I probably don't need assembly that much. It would be fun delving into that again, but once we get the display and file access stuff out of the way, it'll just slow me down with the business logic. That's the spot where you often shell out to scripting languages in more modern systems, so I wouldn't want to go beneath the level of C/Pascal. Although with some clever macros and a lot of data-driven logic, that might still be an option. Might need to go through a few guides/books/manuals again before I make my final decision.

But unless I'm going to bare metal, I'll probably end up with something compiled -- I like some of the more structured BASICs, but it doesn't seem like one of those would be on the menu (or similar languages like Comal). That brings us down to the compiled languages, where I would be most familiar with C -- which on the other hand might be the reason to give something else a try.

So that's probably one of:

- Pascal (Microsoft Pascal, Pascal MT/+, Turbo Pascal 1/2, UCSD)
- C (Desmet, Microsoft, Lattice)
- Forth (F83?)
- PL/1 or PL/M (some Digital Research stuff seems to legally available)
- Modula-2 (always liked it, never got around to do much with it. Logitech and ETH compilers seem available)

I guess it depends a bit on the specific environments/compilers. I guess something with EXE/Overlay support would be useful. Right now, I'm researching my Forth options a bit. I always wanted to get into that a bit more than the basic "calculator" attempts I made in the past, Starting Forth is from '81...
 
C can produce bloated code or C can produce tight code depending on the developer/compiler. One thing I've learned writing C for 8-bit microcontrollers is that there is a cost to the way things are done. This reminds me of an experience I had with Pascal and C back in the late 80's early 90's. I was just messing around writing text to the screen directly and made a small sample program that would move a single character across the screen, one character at a time. In Pascal, you would see it do the move though it was decently fast. In C, it went from here to there and you didn't see the move at all because it was just so much faster. I told myself at the time that Pascal has more overhead to check pointers and such and that must be the reason, but it is really just all about how you do it. In both languages you can drop to assembly without much difficulty (using Borland products), so if something needs optimization, you _can_ optimize it. Sometimes it is a matter of studying the output to see what the compiler did vs. what you thought you asked it to do. I've had the same experience in C where I wanted it to do something, and it was slower than what I wanted so I dropped to assembly (which I'm not super skilled at) to get it done faster. Here is an example - I was messing around with how minimally I could make some screen functions, and the screen has both a character and attribute bytes. It was terribly slow and kludgy to use a memset to set them all and then go back and change all the odd values when you have a 16 bit processor that should be able to do it so quickly, so I wrote the following. If you know assembly you probably have some tips for me on how to improve it even!

Code:
void memsetw(void *dest, unsigned int val, size_t len)
  {
    asm mov dx, es
    asm mov ax, val
    #if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
      asm mov di, dest
      asm push ds
      asm pop es
    #else
      asm les di, dest
    #endif
    asm mov cx, len
    asm rep stosw
    asm mov es, dx
  }
 
Having programmed in C for a number of years one you learn is that it's best not to move things around but if you can move pointers around. Of course this is the same thing in ASM.

Note: I've never liked Pascal or ASM for the 8088/86. The crazy memory layout always bother me. None of that matters when the compiler can hide that.
 
This is approximately the same when you tell MS C to optimize--it will inline simple functions like memcpy and memset. In particular, I note that memcpy, although having byte granularity, will use a combination of movsb for the odd byte and movsw for the remainder.

Here's an example of memcpy inlining in large data mode:

First, the program:

Code:
#include <string.h>

void movetest( char *from, char *to, int howmuch)
{

memcpy( to, from, howmuch);
return;
}

And the generated code:

Code:
_movetest PROC NEAR
; Line 4
*** 000000 55 push bp
*** 000001 8b ec mov bp,sp
*** 000003 57 push di
*** 000004 56 push si
; Line 6
*** 000005 8b 46 04 mov ax,WORD PTR [bp+4]
*** 000008 8b 56 06 mov dx,WORD PTR [bp+6]
*** 00000b 8b 4e 0c mov cx,WORD PTR [bp+12]
*** 00000e 1e push ds
*** 00000f 8b f0 mov si,ax
*** 000011 8e da mov ds,dx
ASSUME DS: NOTHING
*** 000013 c4 7e 08 les di,DWORD PTR [bp+8] ;to
*** 000016 d1 e9 shr cx,1
*** 000018 f3 rep
*** 000019 a5 movsw
*** 00001a 13 c9 adc cx,cx
*** 00001c f3 rep
*** 00001d a4 movsb
*** 00001e 1f pop ds
ASSUME DS: DGROUP
; Line 8
*** 00001f 5e pop si
*** 000020 5f pop di
*** 000021 8b e5 mov sp,bp
*** 000023 5d pop bp
*** 000024 c3 ret
_movetest ENDP

Not worth coding in assembly, at least to me. Note that the segment juggling will go away if "from" and "to" are near pointers, without any tweaking of the source.
 
Back
Top