1
0
mirror of https://github.com/aap/pdp6.git synced 2026-03-09 04:20:05 +00:00

new emulator; will replace the other one eventually

This commit is contained in:
aap
2024-04-14 17:41:05 +02:00
parent 5190890e4a
commit bf1502e9ee
18 changed files with 12232 additions and 0 deletions

11
newemu/Makefile Normal file
View File

@@ -0,0 +1,11 @@
INC=
LIBS=-lpthread -lm -lSDL2
#CFLAGS=-Wall -Wextra -g -O3
#CFLAGS=-g -O3 -mcpu=cortex-a53 -mtune=cortex-a53
CFLAGS=-g -Wall -Wno-parentheses
pdp6: main.c panel6.c pdp6.c tty.c pt.c dis340.c dc.c ut.c ge.c audio.c common.c
cc $(CFLAGS) -o $@ $^ $(INC) $(LIBS)
run: pdp6
./pdp6

27
newemu/args.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef USED
#define USED(x) ((void)x)
#endif
#define SET(x) ((x)=0)
extern char *argv0;
#define ARGBEGIN for((void)(argv0||(argv0=*argv)),argv++,argc--;\
argv[0] && argv[0][0]=='-' && argv[0][1];\
argc--, argv++) {\
char *_args, *_argt;\
char _argc;\
_args = &argv[0][1];\
if(_args[0]=='-' && _args[1]==0){\
argc--; argv++; break;\
}\
_argc = 0;\
while(*_args && (_argc = *_args++))\
switch(_argc)
#define ARGEND SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
#define ARGF() (_argt=_args, _args=(char*)"",\
(*_argt? _argt: argv[1]? (argc--, *++argv): 0))
#define EARGF(x) (_argt=_args, _args=(char*)"",\
(*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0)))
#define ARGC() _argc

66
newemu/audio.c Normal file
View File

@@ -0,0 +1,66 @@
#include "common.h"
#include "pdp6.h"
#include <SDL2/SDL.h>
static SDL_AudioDeviceID dev;
static int nsamples;
static u64 nexttime;
#define SAMPLE_TIME (1000000000/48000)
void
initmusic(void)
{
SDL_AudioSpec spec;
SDL_Init(SDL_INIT_AUDIO);
memset(&spec, 0, sizeof(spec));
spec.freq = 48000;
spec.format = AUDIO_U8;
spec.channels = 1;
spec.samples = 1024; // whatever this is
spec.callback = nil;
dev = SDL_OpenAudioDevice(nil, 0, &spec, nil, 0);
}
void
stopmusic(void)
{
if(dev == 0)
return;
SDL_PauseAudioDevice(dev, 1);
SDL_ClearQueuedAudio(dev);
nsamples = 0;
nexttime = 0;
}
void
svc_music(PDP6 *pdp)
{
u8 s;
if(dev == 0 || nexttime >= simtime)
return;
if(nexttime == 0)
nexttime = simtime + SAMPLE_TIME;
else
nexttime += SAMPLE_TIME;
// queue up a few samples
if(nsamples < 10) {
nsamples++;
// then start playing
if(nsamples == 10)
SDL_PauseAudioDevice(dev, 0);
}
s = 0;
for(int i = 0; i < 6; i++)
if(pdp->mi & (1<<i))
s += 40;
SDL_QueueAudio(dev, &s, 1);
}

781
newemu/chargen.inc Normal file
View File

@@ -0,0 +1,781 @@
enum {
I = 020,
R = 010,
L = 014,
U = 02,
D = 03
};
static int char_na[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I,
R|I, D|I, D|I, D|I, D|I, D|I, D|I,
R|I, U|I, U|I, U|I, U|I, U|I, U|I,
R|I, D|I, D|I, D|I, D|I, D|I, D|I,
R|I, U|I, U|I, U|I, U|I, U|I, U|I,
D|R, D|R, D, D, D, D,
0
};
static int char_A[] = {
I, U|I, U|I, U|I, U|I, U|I, U|R|I,
R|I, R|I, R|D|I, D|I, L, L, L|D|I,
R|I, R|I, R|I, D|I, D|I, D|I, R, R,
0
};
static int char_B[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I, R|I,
R|I, R|I, R|D|I, D|I, L|D|I, L|I, L|I,
D, D, D|I, R|I, R|I, U|R|I, U|I,
D|R, D|R,
0
};
static int char_C[] = {
U|I, U|I, U|I, U|I, U|I, U|R|I, R|I, R|I, D|R|I,
D|L, D|L, D|L, D, D|I,
R|I, R|I, U|R|I, D|R, R,
0
};
static int char_D[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I,
R|I, R|I, R|I, R|D|I, D|I, D|I, D|I, D|I,
L, L, L|D|I, R|I, R|I, R, R, R,
0
};
static int char_E[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I,
R|I, R|I, R|I, R|I,
D|L, D|L, D|L|I,
R|I, R|I, R|I,
D|L, D|L, D|L|I,
R|I, R|I, R|I, R, R,
0
};
static int char_F[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I,
R|I, R|I, R|I, R|I,
D|L, D|L, D|L|I,
R|I, R|I, R|I,
D|L, D|L, D|L,
R, R, R, R, R,
0
};
static int char_G[] = {
U|I, U|I, U|I, U|I, U|I,
U|R|I, R|I, R|I, D|R|I,
D, D|I, L|I, L|I, D|L, D,
D|I, R|I, R|I, U|R|I, U|I, D|R, D|R,
0
};
static int char_H[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I,
D|R, D, D|I, R|I, R|I,
U, U, U|R|I,
D|I, D|I, D|I, D|I, D|I, D|I, R, R,
0
};
static int char_I[] = {
U, U, U, U, U, U|R|I,
R|I, R|I, D|L|I,
D|I, D|I, D|I, D|I, D|L|I,
R|I, R|I, R, R, R,
0
};
static int char_J[] = {
U|I, D|R|I, R|I, R|I,
U|R|I, U|I, U|I, U|I, U|I, U|I,
D|R, D|R, D, D, D, D,
0
};
static int char_K[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I,
R, R, R, R|I,
D|L|I, D|L|I, D|L|I,
D|R|I, D|R|I, D|R|I, R, R,
0
};
static int char_L[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I,
D|R, D, D, D, D, D|I,
R|I, R|I, R|I, R, R,
0
};
static int char_M[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I,
D|R|I, D|R|I, U|R|I, U|R|I,
D|I, D|I, D|I, D|I, D|I, D|I, R, R,
0
};
static int char_N[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I,
D|R|I, D|R|I, D|R|I,
U, U, U|R|I,
D|I, D|I, D|I, D|I, D|I, D|I, R, R,
0
};
static int char_O[] = {
U|I, U|I, U|I, U|I, U|I,
U|R|I, R|I, R|I,
D|R|I, D|I, D|I, D|I, D|I,
L, L, D|L|I, R|I, R|I, R, R, R,
0
};
static int char_P[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I,
R|I, R|I, R|I,
D|R|I, D|I,
D|L|I, L|I, L|I,
D|R, D|R, D|R, R, R,
0
};
static int char_Q[] = {
U|I, U|I, U|I, U|I, U|I,
U|R|I, R|I, R|I,
D|R|I, D|I, D|I, D|I,
L, L|I, D|L, D|I,
R|I, R|I, U|I, R|I, D|I, R, R,
0
};
static int char_R[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I,
R|I, R|I, R|I,
D|R|I, D|I,
D|L|I, L|I, L|I,
D|R|I, D|R|I, D|R|I, R, R,
0
};
static int char_S[] = {
U|I, D|R|I, R|I, R|I, U|R|I, U|I,
U|L|I, L|I, L|I, U|L|I, U|I,
U|R|I, R|I, R|I, D|R|I, D|R, D|R, D, D, D,
0
};
static int char_T[] = {
U, U, U, U, U, U|I,
R|I, R|I, R|I, R|I,
D|L, L|I,
D|I, D|I, D|I, D|I, D|I,
R, R, R, R,
0
};
static int char_U[] = {
U|I, U|I, U|I, U|I, U|I, U|I,
R, R, R, R|I,
D|I, D|I, D|I, D|I, D|I,
L, L, L|D|I, R|I, R|I, R, R, R,
0
};
static int char_V[] = {
R, R|I, U|L|I, U|L|I, U|I, U|I, U|I, U|I,
R, R, R, R|I,
D|I, D|I, D|I, D|I, D|L|I, D|L|I, R, R, R, R,
0
};
static int char_W[] = {
I, U|I, R|I, U|R|I, L, L|I, U|I, U|I, U|I, U|I,
R, R, R, R|I,
D|I, D|I, D|I, D|I, D|I, L|I, D|R|I, R, R,
0
};
static int char_X[] = {
I, U|R|I, U|R|I, U|I, U|I, U|L|I, U|L|I,
R, R, R, R|I,
D|L|I, D, D, D, D|I, D|R|I, R, R,
0
};
static int char_Y[] = {
U, U, U, U, U, U|I,
R, R, R, R|I, D|L|I,
L, L|I,
D|R|I, D|I, D|I, D|I, D|I, R, R, R, R,
0
};
static int char_Z[] = {
I, U|I, U|R|I, U|I, L|I,
U, U, U|I,
R|I, R|I, R|I, R|I,
D|I, D|L|I, D|R|I, L|I, L|I,
D, D, D|L|I,
R|I, R|I, R|I, R, R,
0
};
static int char_a[] = {
R, R|I, L|I, U|L|I, U|I, U|I, U|R|I,
R|I, R|I, D|I, D|I, D|I, D|R|I, R, R,
0
};
static int char_b[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I,
D, D|R|I, R|I, R|I, D|R|I, D|I, D|I,
D|L, L, L|I, R|I, R|I, R, R, R,
0
};
static int char_c[] = {
U|I, U|I, U|I, U|R|I, R|I, R|I, D|R|I,
D|L, D|L, D|L|I,
R|I, R|I, U|R|I, D|R, R,
0
};
static int char_d[] = {
U|I, U|I, U|I, U|R|I, R|I, R|I, R|U|I, U|I, D,
D|I, D|I, D|I, D|I, L, L, D|L|I, R|I, R|I, R|I, R, R,
0
};
static int char_e[] = {
U|I, U|I, U|I, U|R|I, R|I, R|I, D|R|I,
D|I, L|I, L|I, L|I, D, D|I, R|I, R|I, R, R, R,
0
};
static int char_f[] = {
R|I, U|I, U|I, U|L|I, R|I, R|I,
U|L|I, U|I, U|R|I, R|I, D|R|I,
D|R, D|R, D, D, D,
0
};
static int char_g[] = {
U|I, U|I, U|I,
U|R|I, R|I, R|I, D|R|I, D|I, D|I, D|I, D|I,
D|L|I, L|I, L|I, U,
U|I, R|I, R|I, R, R, R,
0
};
static int char_h[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I,
D|R, D|I, R|I, R|I,
D|R|I, D|I, D|I, D|I, R, R,
0
};
static int char_i[] = {
U, U, U, U|R|I, U, U|R|I,
D, D|I, D|I, D|I, D|I, D|L|I,
R|I, R|I, R, R, R,
0
};
/*
_ _ _ _ O
_ _ _ _ _
_ _ _ _ O
_ _ _ _ O
_ _ _ _ O
_ _ _ _ O
. _ _ _ O
_ _ _ _ O
_ O O O _
*/
static int char_j[] = {
D|R, D|I, R|I, R|I, U|R|I,
U|I, U|I, U|I, U|I, U|I, U, U|I,
D|R, D|R, D, D, D, D,
0
};
static int char_k[] = {
I, U|I, U|I, U|I, U|I, U|I, U|I,
R, D|R, D|R|I,
D|L|I, D|L|I,
R|I, D|R|I, D|R|I, R, R,
0
};
static int char_l[] = {
U, U, U, U, U, U|R|I,
R|I, D|I,
D|I, D|I, D|I, D|I, D|L|I,
R|I, R|I, R, R, R,
0
};
static int char_m[] = {
I, U|I, U|I, U|I, U|I,
R|I, D|R|I, D|I, D|I, D|I,
U|R, U, U, U|I, D|R|I,
D|I, D|I, D|I, R, R,
0
};
static int char_n[] = {
I, U|I, U|I, U|I, U|I,
D|R|I, U|R|I, R|I,
D|R|I, D|I, D|I, D|I, R, R,
0
};
static int char_o[] = {
U|I, U|I, U|I,
U|R|I, R|I, R|I,
D|R|I, D|I, D|I,
L, L, D|L|I, R|I, R|I, R, R, R,
0
};
static int char_p[] = {
D, D|I, U|I, U|I, U|I, U|I, U|I, U|I,
R|I, R|I, R|I,
D|R|I, D|I, D|I,
D|L|I, L|I, L|I,
R, R, R, R, R,
0
};
static int char_q[] = {
U|I, U|I, U|I,
U|R|I, R|I, R|I, R|I,
D|I, D|I, D|I, D|I, D|I, D|I,
U|L, U|L, L|I, R|I, R|I,
R, R, R,
0
};
static int char_r[] = {
I, U|I, U|I, U|I, U|I,
D|R|I, U|R|I, R|I, D|R|I,
D|R, D|R, D,
0
};
static int char_s[] = {
I, R|I, R|I, R|I, U|R|I,
U|L|I, L|I, L|I, U|L|I,
U|R|I, R|I, R|I, R|I, D|R, D|R, D, D,
0
};
static int char_t[] = {
U|R|I, U|I, U|I, U|L|I, R|I, U|I, U|I,
D|R, D|I, D, D, D,
D|I, R|I, U|R|I, D|R, R,
0
};
static int char_u[] = {
U|I, U|I, U|I, U|I,
R, R, R, R|I,
D|I, D|I, D|I, L|I,
L|D|I, L|I, R, R, R|I, R, R,
0
};
static int char_v[] = {
R, R|I, U|L|I, U|L|I, U|I, U|I,
R, R, R, R|I,
D|I, D|I, D|L|I, D|L|I, R, R, R, R,
0
};
static int char_w[] = {
R|I, U|L|I, U|I, U|I, U|I,
D|R, R|I, D|I, D|I, D|R|I,
U|R|I, U|I, U|I, U|I, D|R, D|R, D, D,
0
};
static int char_x[] = {
I, U|R|I, U|R|I, U|R|I, U|R|I,
L, L, L,
L|I, D|R|I, D|R|I, D|R|I, D|R|I, R, R,
0
};
static int char_y[] = {
U|I, U|I, U|I, U|I,
R, R, R, R|I, D|I, D|I, D|I, D|I, D|I,
D|L|I, L|I, L|I, U,
U|I, R|I, R|I, R, R, R,
0
};
static int char_z[] = {
I, U|R|I, U|I, R|I, R|I,
U|I, U|R|I, L|I, L|I, L|I, L|I,
D|R, D, D, D|I, R|I, R|I, R|I, R, R,
0
};
static int char_null[] = {
U, U|I, U|I, R|I, U|L|I,
U|R|I, R|I, D|I, U|R|I,
D|R|I, D|I, L|I, D|R|I,
L, L|I, D|L|I, R|I, R|I, D|R, R, R,
0
};
static int char_ex[] = {
R, R|I, U, U|I, U|I, U|I, U|I, U|I,
D|R, D|R, D|R, D|R, D, D,
0
};
static int char_dq[] = {
U, U, U, U|R|I, U|I, U|I,
R, R|I, D|I, D|I, D|R, D|R, D|R, D,
0
};
static int char_sh[] = {
R, R|I, U|I, U|I, L|I, U|R|I, U|I, L|I, U|R|I, U|I,
R, R|I, D|I, D|R|I, L|I, L|I, D|R|I, D|R|I,
L|I, L|I, D|R|I, D|I, R, R, R,
0
};
static int char_dl[] = {
U|I, D|R|I, R|I, U|I, D|R|I, U|R|I, U|I,
U|L|I, D|L|I, U|I, U|I, D|L|I, U|L|I, U|I,
U|R|I, R|I, D|I, U|R|I, D|R|I, D|R, D|R, D, D, D,
0
};
static int char_pr[] = {
I, U|I, U|R|I, U|R|I, U|R|I, U|R|I, U|I,
L|I, L|I, L|I, L|I, D|I, R|I,
D|R, D|R, D,
D|I, R|I, D|L|I, R|I, R, R,
0
};
static int char_et[] = {
R|I, U|L|I, U|I, U|R, U|R|I, U|I, U|L|I,
D|L|I, D|I, D|R|I, D|R|I, D|I, D|I, U|R|I, U|R|I,
D, D|I, R, R,
0
};
static int char_sq[] = {
U, U, U, U, U|R|I, U|I,
R|I, D|I, D|I, D|R, D|R, D|R, D|R,
0
};
static int char_lp[] = {
R, R, R|I, U|L|I, U|L|I, U|I, U|I, U|R|I, U|R|I,
D|R, D|R, D|R, D, D, D,
0
};
static int char_rp[] = {
U, U, U, U, U, U|R|I,
D|R|I, D|R|I, D|I, D|I, D|L|I, D|L|I,
R, R, R, R, R,
0
};
static int char_as[] = {
U|I, U|R|I, U|R|I, U|L|I, U|L|I, R,
R|I, R, R|I, D|L|I, L|I, D,
D|I, D|I, U|R|I, D|R|I, D|R, R,
0
};
static int char_pl[] = {
U, U, U|I, R|I, U|R|I, U|I,
D|R, D|R|I, L|I, L|I, D|I, D|I,
D|R, R, R, R,
0
};
static int char_cm[] = {
U, U|R|I, U|I, R|I, D|I, D|I, D|L|I, R, R, R, R, R,
0
};
static int char_mi[] = {
U, U, U|I, R|I, R|I, R|I, R|I, D|R, D|R, D,
0
};
static int char_pe[] = {
R|I, U|I, R|I, D|I, R, R, R, R,
0
};
static int char_sl[] = {
U|I, U|R|I, U|R|I, U|R|I, U|R|I,
D|R, D|R, D, D, D,
0
};
static int char_0[] = {
U|I, U|R|I, L|I, U|I, U|I, U|I,
U|R|I, R|I, R|I, D|R|I, D|I, L|I, D|L|I,
R, R|I, D|I, D|I, D|L|I, L|I, L|I,
R, R, R, R, R,
0
};
static int char_1[] = {
U, U, U, U, U|R|I, U|R|I, D|I,
D|I, D|I, D|I, D|I, D|L|I, R|I, R|I, R,
R, R,
0
};
static int char_2[] = {
U, U, U, U, U|I, U|R|I, R|I, R|I,
D|R|I, D|I, D|L|I, L|I, L|I, D|L|I, D|I, D|I,
R|I, R|I, R|I, R|I, R, R,
0
};
static int char_3[] = {
U|I, D|R|I, R|I, R|I, U|R|I, U|I, U|L|I,
U|R|I, U|I, U|L|I, L|I, L|I, D|L|I,
D|R, D|R|I, D|R, D|R, D|R, R,
0
};
static int char_4[] = {
U, U, U|I, R|I, R|I, U|L|I, U|R|I, U|R|I,
D|I, D|I, D|R|I, L|I, D|I, D|I, D|I, R, R, R,
0
};
static int char_5[] = {
U|I, D|R|I, R|I, R|I, U|R|I, U|I, U|L|I, L|I, L|I,
U|L|I, U|I, U|I, R|I, R|I, R|I, R|I,
D|R, D|R, D, D, D, D,
0
};
static int char_6[] = {
R|I, U|L|I, U|I, U|R|I, L|I, U|I, U|I,
U|R|I, R|I, R|I, D|R|I, D|L, D|L|I, R|I,
D|R|I, D|I, L, D|L|I, R|I, R, R, R,
0
};
static int char_7[] = {
I, U|I, U|R|I, U|L, U, U|I, U|I,
R|I, R|I, R|I, R|I, D|I, D|L|I, D|L|I,
D|R, D|R, D|R, R,
0
};
static int char_8[] = {
R|I, U|L|I, U|I, U|R|I, U|L|I, U|I, U|R|I,
R|I, R|I, D|R|I, D|I, L, D|L|I, R|I, D|R|I,
D|I, L, D|L|I, R|I, R, R, R,
0
};
static int char_9[] = {
U|I, D|R|I, R|I, R|I, U|R|I, U|I, U|I, U|I, U|I,
U|L|I, L|I, L|I, D|L|I, D|I, D|R|I, R|I, R|I,
D|R, D|R, D|R,
0
};
static int char_cl[] = {
U, U, U, U|R|I, R|I, D|I, L|I,
D, D|I, R|I, D|L|I, R|I, R, R, R, R,
0
};
static int char_sm[] = {
U, U, U, U, U, U|R|I, R|I, D|I, L|I,
D, D|I, R|I, D|L|I, R|I, D|I, D|L|I, R, R, R, R, R,
0
};
static int char_la[] = {
R, R, R|I, U|L|I, U|L|I, U|L|I,
U|R|I, U|R|I, U|R|I,
D|R, D|R, D|R, D, D, D,
0
};
static int char_eq[] = {
U, U|I, U, U|I, R|I, D, D|I,
R|I, U, U|I, R|I, D, D|I, R|I,
U, U|I, D|R, D|R, D, D,
0
};
static int char_ra[] = {
R|I, U|R|I, U|R|I, U|R|I,
U|L|I, U|L|I, U|L|I,
D|R, D|R, D|R, D|R, D|R, D,
0
};
static int char_qs[] = {
U, U, U, U, U|I, U|R|I, R|I, R|I,
D|R|I, D|I, D|L|I, L|I,
D|I, D|I, D|I, R, R, R, R,
0
};
static int char_us[] = {
I, R|I, R|I, R|I, R|I, R, R,
0
};
static int char_bar[] = {
R, R|I, U|I, U|I, U|I, U|I, U|I, U|I,
D|R, D|R, D|R, D|R, D, D,
0
};
static int char_bs[] = {
U, U, U, U, U|I,
D|R|I, D|R|I, D|R|I, D|R|I,
D|R, R,
0
};
static int char_Lb[] = {
R, I, R|I, R|I, U|L, L|I,
U|I, U|I, U|I, U|I, U|I,
R|I, R|I, D|R, D|R, D|R, D, D, D,
0
};
static int char_Rb[] = {
U, R|U, U, U, U, U|I, R|I, R|I,
D|I, D|I, D|I, D|I, D|L, D|L|I,
R|I, R|I, U|I, D|R, R, R,
0
};
static int char_LB[] = {
R, R, R|I, U|L|I, U|I, U|L|I, U|R|I, U|I, U|R|I,
D|R, D|R, D|R, D, D, D,
0
};
static int char_RB[] = {
U|R, U, U, U, U, U|I,
D|R|I, D|I, D|R|I, D|L|I, D|I, D|L|I,
R, R, R, R, R,
0
};
static int char_Ra[] = {
U, U, U|I, R|I, R|I, U, U|I,
D|R|I, D|R|I, L|I, D|I, D|L|I,
D|R, R, R, R,
0
};
static int char_La[] = {
R, U|R|I, L|U|I, L|U|I, R|I, U|I, R|U|I,
D, D|I, R|I, R|I, D|R, D|R, D,
0
};
static int char_Da[] = {
U, U|I, D|R|I, D|R|I, U|I, U|I, U|I, U|I, U|I, U|I,
D|R, D|R, D, D|I, D|L|I, D|R, R, R,
0
};
/*
static int char_Ua[] = {
R, R|I, U|I, U|I, U|I, U|I, R, R|I,
U|L|I, L|I, U|I, D|L|I, D|L|I,
D, D, D, D,
0
};
*/
static int char_Ua[] = {
R, R|I, U|I, U|I, U|I, U|I, L, L|I,
U|R|I, R|I, U|I, D|R|I, D|R|I,
D|R, D|R, D, D,
0
};
static int char_tl[] = {
U, U, U, U, U|I, U|R|I, D|R|I, D|R|I, U|R|I,
D|R, D|R, D, D, D,
0
};
static int char_tk[] = {
U|L, U|L, U|L, U|L, U|L, U|I, D|R|I, D|R|I,
D|L, D|L, D|L, D,
0
};
static int char_ci[] = {
U|L, U|L, U|L, U|L|I, L, U|I, U|R|I,
D|R|I, D|R|I, D|R, D|R, D, D,
0
};
static int char_back[] = {
L, L, L, L, L, L,
0
};
static int char_dn[] = {
D, D, D, D,
0
};
static int char_up[] = {
U, U, U, U,
0
};
static int char_sp[] = { R, R, R, R, R, R, 0 };
static int char_lf[] = { D, D, D, D, D, D, D, D, D, D, D, 0 };
static int char_cr[] = { 0100, 0 };
static int char_esc[] = { 040 };
static int char_si[] = { 0200 };
static int char_so[] = { 0400 };
static int *chars[] = {
char_null, char_A, char_B, char_C, char_D, char_E, char_F, char_G,
char_H, char_I, char_J, char_K, char_L, char_M, char_N, char_O,
char_P, char_Q, char_R, char_S, char_T, char_U, char_V, char_W,
char_X, char_Y, char_Z, char_lf, char_cr, char_si, char_so, char_esc,
char_sp, char_ex, char_dq, char_sh, char_dl, char_pr, char_et, char_sq,
char_lp, char_rp, char_as, char_pl, char_cm, char_mi, char_pe, char_sl,
char_0, char_1, char_2, char_3, char_4, char_5, char_6, char_7,
char_8, char_9, char_cl, char_sm, char_la, char_eq, char_ra, char_qs,
/* TODO: lower case. some of the unknowns */
char_null, char_a, char_b, char_c, char_d, char_e, char_f, char_g,
char_h, char_i, char_j, char_k, char_l, char_m, char_n, char_o,
char_p, char_q, char_r, char_s, char_t, char_u, char_v, char_w,
char_x, char_y, char_z, char_lf, char_cr, char_si, char_so, char_esc,
char_sp, char_na, char_na, char_tl, char_na, char_na, char_Ua, char_Ra,
char_Da, char_La, char_bs, char_Lb, char_Rb, char_LB, char_RB, char_na,
char_us, char_na, char_bar, char_na, char_na, char_na, char_tk, char_ci,
char_na, char_na, char_back, char_dn, char_na, char_na, char_na, char_up,
};

240
newemu/common.c Normal file
View File

@@ -0,0 +1,240 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include "common.h"
void
panic(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
exit(1);
}
int
hasinput(int fd)
{
fd_set fds;
struct timeval timeout;
if(fd < 0) return 0;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(fd, &fds);
return select(fd+1, &fds, NULL, NULL, &timeout) > 0;
}
int
dial(const char *host, int port)
{
char portstr[32];
int sockfd;
struct addrinfo *result, *rp, hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
snprintf(portstr, 32, "%d", port);
if(getaddrinfo(host, portstr, &hints, &result)){
perror("error: getaddrinfo");
return -1;
}
for(rp = result; rp; rp = rp->ai_next){
sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if(sockfd < 0)
continue;
if(connect(sockfd, rp->ai_addr, rp->ai_addrlen) >= 0)
goto win;
close(sockfd);
}
freeaddrinfo(result);
perror("error");
return -1;
win:
freeaddrinfo(result);
return sockfd;
}
int
serve1(int port)
{
int sockfd, confd;
socklen_t len;
struct sockaddr_in server, client;
int x;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
perror("error: socket");
return -1;
}
x = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void *)&x, sizeof x);
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
if(bind(sockfd, (struct sockaddr*)&server, sizeof(server)) < 0){
perror("error: bind");
return -1;
}
listen(sockfd, 5);
len = sizeof(client);
confd = accept(sockfd, (struct sockaddr*)&client, &len),
close(sockfd);
if(confd >= 0)
return confd;
perror("error: accept");
return -1;
}
void
nodelay(int fd)
{
int flag = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
}
void*
createseg(const char *name, size_t sz)
{
int fd;
void *p;
mode_t mask = umask(0);
fd = open(name, O_RDWR|O_CREAT, 0666);
umask(mask);
// if we try to open a /tmp file owned by another user
// with O_CREAT, the above will fail (even for root).
// so try again without O_CREAT
if(fd == -1)
fd = open(name, O_RDWR);
if(fd == -1) {
fprintf(stderr, "couldn't open file %s\n", name);
return nil;
}
ftruncate(fd, sz);
p = mmap(nil, sz, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(p == MAP_FAILED) {
fprintf(stderr, "couldn't mmap file\n");
return nil;
}
return p;
}
void*
attachseg(const char *name, size_t sz)
{
int fd;
void *p;
fd = open(name, O_RDWR);
if(fd == -1) {
fprintf(stderr, "couldn't open file %s\n", name);
return nil;
}
p = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(p == MAP_FAILED) {
fprintf(stderr, "couldn't mmap file\n");
return nil;
}
return p;
}
static struct timespec starttime;
void
inittime(void)
{
clock_gettime(CLOCK_MONOTONIC, &starttime);
}
u64
gettime(void)
{
struct timespec tm;
u64 t;
clock_gettime(CLOCK_MONOTONIC, &tm);
tm.tv_sec -= starttime.tv_sec;
t = tm.tv_nsec;
t += (u64)tm.tv_sec * 1000 * 1000 * 1000;
return t;
}
void
nsleep(u64 ns)
{
struct timespec tm;
tm.tv_sec = ns / (1000 * 1000 * 1000);
tm.tv_nsec = ns % (1000 * 1000 * 1000);
nanosleep(&tm, nil);
}
static int
isdelim(char c)
{
return c == '\0' || strchr(" \t\n;'\"", c) != nil;
}
/* have to free argv[0] and argv to clean up */
char**
split(char *line, int *pargc)
{
int argc, n;
char **argv, *lp, delim;
n = strlen(line)+1;
// just allocate enough
lp = (char*)malloc(2*n);
argv = (char**)malloc(sizeof(char*)*n);
argc = 0;
for(; *line; line++) {
while(isspace(*line)) line++;
if(*line == '\0')
break;
argv[argc++] = lp;
if(*line == '"' || *line == '\'') {
delim = *line++;
while(*line && *line != delim) {
if(*line == '\\')
line++;
*lp++ = *line++;
}
} else {
while(!isdelim(*line)) {
if(*line == '\\')
line++;
*lp++ = *line++;
}
}
*lp++ = '\0';
}
if(pargc) *pargc = argc;
argv[argc++] = nil;
return argv;
}

34
newemu/common.h Normal file
View File

@@ -0,0 +1,34 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
//typedef uint64_t u64;
typedef unsigned long long u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
typedef int64_t i64;
typedef int32_t i32;
typedef int16_t i16;
typedef int8_t i8;
#define nil NULL
#define nelem(array) (sizeof(array)/sizeof(array[0]))
void panic(const char *fmt, ...);
int hasinput(int fd);
int dial(const char *host, int port);
int serve1(int port);
void nodelay(int fd);
void *createseg(const char *name, size_t sz);
void *attachseg(const char *name, size_t sz);
void inittime(void);
u64 gettime(void);
void nsleep(u64 ns);
#define NEVER (~0)
char **split(char *line, int *pargc);

182
newemu/dc.c Normal file
View File

@@ -0,0 +1,182 @@
#include "common.h"
#include "pdp6.h"
#define IOB pdp->iob
static void calc_dc_req(PDP6 *pdp, Dc136 *dc);
static void
dbda_swap(Dc136 *dc)
{
dc->dbda_move = 0;
dc->darq = 0;
dc->dbrq = 1;
if(dc->inout) // out
dc->da = dc->db;
else {
dc->db = dc->da;
dc->da = 0;
}
//printf("DB req %012llo\n", dc->db);
}
/*
* bits per char ch mode shifts per char chars per word
* 6 0 0 0 6
* 12 1 0 2 3
* 18 1 1 3 2
* 36 0 1 0 1
*/
#define NSHIFT ((0xE0 >> (dc->ch_mode*2)) & 3)
#define NCHARS ((02316 >> (dc->ch_mode*3)) & 7)
#define DC_SCT_DONE (dc->sct == NSHIFT)
#define DC_CCT_DONE (dc->cct == NCHARS-1)
static void
dashcp0(Dc136 *dc, Word inp)
{
cp0:
// DASH CP0
if(dc->darq)
dc->data_clbd = 1;
// 1μs dly
// DASH CP1
if(DC_CCT_DONE) {
dc->cct = 0;
if(dc->dbda_move && !dc->darq)
dbda_swap(dc);
else
dc->darq = 1;
} else if(DC_SCT_DONE) {
// CCT CONT
dc->sct = 0;
dc->cct = (dc->cct+1) & 7;
} else {
// SCT CONT
dc->sct = (dc->sct+1) & 3;
// DASH LT
dc->da = dc->da<<6 | inp;
goto cp0;
}
}
int
dctkgv(Dc136 *dc, int dev, int ch, int rt)
{
int ret;
if(dc->device != dev)
return 0;
switch(dev) {
case 1: case 2:
if(rt) {
ret = dc->da & 077;
ret = (ret<<3 | ret>>3) & 077;
ch = (ch<<3 | ch>>3) & 077;
dc->da = dc->da>>6 | (Word)ch<<30;
} else {
case 3: case 4:
ret = (dc->da>>30) & 077;
ch &= 077;
dc->da = dc->da<<6 | ch;
}
break;
default: // shouldn't happen
return 0;
}
dc->da &= FW;
dashcp0(dc, ch);
calc_dc_req(dc->pdp, dc);
return ret;
}
static void
handle_dc(PDP6 *pdp, IOdev *dev, int cmd)
{
Dc136 *dc = (Dc136*)dev->dev;
bool s0 = dc->darq && dc->dbda_move;
switch(cmd) {
case IOB_RESET:
dc->db = 0;
dc->da = 0; // hack so DB isn't overwritten again
case IOB_CONO_CLR:
dc->sct = 0;
dc->cct = 0;
dc->data_clbd = 0;
dc->dbda_move = 0;
dc->darq = 0;
dc->dbrq = 0;
dc->inout = 0;
dc->ch_mode = 0;
dc->device = 0;
dc->pia = 0;
dc->db = dc->da;
dc->da = 0;
break;
case IOB_CONO_SET:
if(IOB & F23) dc->data_clbd = 1;
if(IOB & F24) dc->dbda_move = 1;
if(IOB & F25) dc->darq = 1;
if(IOB & F26) dc->dbrq = 1;
if(IOB & F27) dc->inout = 1;
dc->ch_mode |= (IOB>>6)&3;
dc->device |= (IOB>>3)&7;
dc->pia |= IOB&7;
break;
case IOB_DATAO_CLR:
dc->db = 0;
dc->dbrq = 0;
break;
case IOB_DATAO_SET:
dc->db |= IOB;
dc->dbda_move = 1;
break;
case IOB_DATAI:
IOB |= dc->db;
dc->dbrq = 0;
dc->dbda_move = 1;
break;
case IOB_STATUS:
IOB |= dc->cct<<13;
if(dc->data_clbd) IOB |= F23;
if(dc->dbda_move) IOB |= F24;
if(dc->darq) IOB |= F25;
if(dc->dbrq) IOB |= F26;
if(dc->inout) IOB |= F27;
IOB |= dc->ch_mode<<6;
IOB |= dc->device<<3;
IOB |= dc->pia;
break;
}
bool s1 = dc->darq && dc->dbda_move;
if(s1 && !s0)
dbda_swap(dc);
calc_dc_req(pdp, dc);
}
static Dc136 dc;
static IOdev dc_dev = { 0, 0200, &dc, handle_dc, nil };
static void
calc_dc_req(PDP6 *pdp, Dc136 *dc)
{
setreq(pdp, &dc_dev, dc->pia && dc->dbrq ? 0200>>dc->pia : 0);
}
Dc136*
attach_dc(PDP6 *pdp)
{
dc.pdp = pdp;
installdev(pdp, &dc_dev);
return &dc;
}

632
newemu/dis340.c Normal file
View File

@@ -0,0 +1,632 @@
#include "common.h"
#include "pdp6.h"
#include <unistd.h>
enum Modes
{
PM,
XYM,
SM,
CM,
VM,
VCM,
IM,
SBM
};
struct Dis340
{
int fd;
/* 344 interface for PDP-6.
* no schematics unfortunately */
int pia_data;
int pia_spec;
Word ib; /* interface buffer */
int ibc; /* number of words in IB */
/* 340 display and 342 char gen */
Hword br; /* 18 bits */
int mode; /* 3 bits */
int i; /* intensity - 3 bits */
int sz; /* scale - 2 bits */
int brm; /* 7 bits */
int s; /* shift - 4 bits */
int x, y; /* 10 bits */
/* flip flops */
int stop;
int halt;
int move;
int lp_find;
int lp_flag;
int lp_enable;
int rfd;
int hef, vef;
/* br shifted for IM and CM */
int pnts;
int chrs;
/* values for BRM counting */
int brm_add;
int brm_comp;
int penx, peny;
int pen;
/* 342 char gen */
int shift;
int *cp; /* current char pointer */
u64 simtime, lasttime;
u64 inputtimer;
int state;
int pnt;
u32 cmdbuf[128];
u32 ncmds;
};
#define LDB(p, s, w) ((w)>>(p) & (1<<(s))-1)
#define IOB pdp->iob
static void calc_dis_req(PDP6 *pdp, Dis340 *dis);
static void
addcmd(Dis340 *dis, u32 cmd)
{
dis->cmdbuf[dis->ncmds++] = cmd;
if(dis->ncmds == nelem(dis->cmdbuf)) {
if(write(dis->fd, dis->cmdbuf, sizeof(dis->cmdbuf)) < sizeof(dis->cmdbuf))
dis->fd = -1;
dis->ncmds = 0;
}
}
static void
agedisplay(Dis340 *dis)
{
if(dis->fd < 0)
return;
u32 cmd = 511<<23;
assert(dis->lasttime <= dis->simtime);
u64 dt = (dis->simtime - dis->lasttime)/1000;
while(dt >= 511) {
dis->lasttime += 511*1000;
addcmd(dis, cmd);
dt = (dis->simtime - dis->lasttime)/1000;
}
}
static void
intensify(Dis340 *dis)
{
if(dis->pen && dis->lp_enable) {
int dx = dis->penx - dis->x;
int dy = dis->peny - dis->y;
if(dx*dx + dy*dy <= 4)
dis->lp_find = 1;
}
if(dis->fd >= 0){
agedisplay(dis);
u32 cmd;
cmd = dis->x;
cmd |= dis->y<<10;
cmd |= dis->i<<20;
int dt = (dis->simtime - dis->lasttime)/1000;
cmd |= dt<<23;
dis->lasttime = dis->simtime;
addcmd(dis, cmd);
}
}
enum {
ST_IDLE,
ST_DATA_SYNC,
ST_READ_TO_S,
ST_DLY_IDP,
ST_IDP,
ST_XY_INTENSIFY,
ST_SEQ_DLY,
ST_CHAR,
ST_CHAR_INT,
ST_RFD,
};
static void
rfd(Dis340 *dis)
{
dis->rfd = 1;
dis->hef = 0;
dis->vef = 0;
}
static void
escape(Dis340 *dis)
{
dis->mode = 0;
dis->lp_find = 0;
}
static void
initiate(Dis340 *dis)
{
dis->shift = 0;
dis->lp_enable = 0; // TODO: not in schematics?
dis->lp_find = 0;
dis->lp_flag = 0;
dis->stop = 0;
escape(dis);
dis->state = ST_RFD;
}
static void
resume(Dis340 *dis)
{
dis->lp_enable = 0;
dis->lp_find = 0;
dis->lp_flag = 0;
if(dis->mode != CM) {
dis->simtime += 1000;
dis->state = ST_SEQ_DLY;
}
}
/* figure out add and complement values for COUNT BRM */
static void
initbrm(Dis340 *dis)
{
int m;
int dx, dy, d;
dis->brm_add = 1;
dx = LDB(0, 7, dis->br);
dy = LDB(8, 7, dis->br);
d = dx > dy ? dx : dy;
for(m = 0100; m > 040; m >>= 1)
if(d & m)
break;
else
dis->brm_add *= 2;
dis->brm_comp = dis->brm_add - 1;
}
static void
read_to_mode(Dis340 *dis)
{
dis->mode = LDB(13, 3, dis->br);
if(dis->br & 0010000)
dis->lp_enable = !!(dis->br & 04000);
}
static void
shift_s(Dis340 *dis)
{
dis->s >>= 1;
dis->pnts <<= 4;
dis->chrs <<= 6;
}
static void
count_brm(Dis340 *dis)
{
dis->brm = ((dis->brm+dis->brm_add) ^ dis->brm_comp) & 0177;
shift_s(dis);
}
static void
count_x(Dis340 *dis, int s, int r, int l)
{
if(r) dis->x += s;
if(l) dis->x -= s;
if(r || l) dis->move = dis->mode != CM;
if(dis->x >= 1024 || dis->x < 0) dis->hef = 1;
dis->x &= 01777;
if(dis->mode == IM && dis->s&1)
dis->halt = 1;
}
static void
count_y(Dis340 *dis, int s, int u, int d)
{
if(u) dis->y += s;
if(d) dis->y -= s;
if(u || d) dis->move = dis->mode != CM; // actually in count_x
if(dis->y >= 1024 || dis->y < 0) dis->vef = 1;
dis->y &= 01777;
dis->lp_flag |= dis->lp_find && dis->lp_enable;
}
static void
getdir(int brm, int xy, int c, int *pos, int *neg)
{
int dir;
int foo;
foo = ~brm & c;
dir = foo&0001 && xy&0100 ||
foo&0002 && xy&0040 ||
foo&0004 && xy&0020 ||
foo&0010 && xy&0010 ||
foo&0020 && xy&0004 ||
foo&0040 && xy&0002 ||
foo&0100 && xy&0001;
*pos = 0;
*neg = 0;
if(dir){
if(xy & 0200)
*neg = 1;
else
*pos = 1;
}
}
#include "chargen.inc"
static void
cycle_dis(PDP6 *pdp, IOdev *dev, int pwr)
{
Dis340 *dis = (Dis340*)dev->dev;
int halt, pnt, r, l, u, d, c, brm;
if(!pwr) {
dis->simtime = simtime;
agedisplay(dis);
return;
}
agedisplay(dis);
if(dis->inputtimer < simtime) {
dis->inputtimer = simtime + 30000000;
if(hasinput(dis->fd)) {
u32 cmds[512];
int n = read(dis->fd, cmds, sizeof(cmds));
n /= 4;
for(int i = 0; i < n; i++) {
u32 cmd = cmds[i];
dis->peny = cmd & 01777;
dis->penx = (cmd>>10) & 01777;
dis->pen = (cmd>>20) & 1;
}
}
}
int doreq = 0;
// catch up with CPU
while(dis->simtime < simtime) {
doreq = 1;
switch(dis->state) {
case ST_IDLE:
if(dis->rfd && dis->ibc > 0)
dis->state = ST_DATA_SYNC;
else
dis->simtime = simtime;
break;
case ST_DATA_SYNC:
// CLR BR
dis->br = 0;
dis->rfd = 0;
// CLR BRM
dis->brm = 0;
dis->halt = 0;
dis->move = 0;
dis->s = 0; // CLEAR S
dis->hef = 0; // CLR CF
dis->vef = 0; // CLR CF
dis->simtime += 2800;
dis->state = ST_READ_TO_S;
break;
case ST_READ_TO_S:
// READ TO S
dis->lp_flag |= dis->lp_find && dis->lp_enable;
if(dis->mode == IM) dis->s |= 010;
if(dis->mode == CM) dis->s |= 004;
// LOAD BR
dis->br |= dis->ib>>18 & RT;
dis->pnts = dis->br;
dis->chrs = dis->br;
initbrm(dis);
// SHIFT IB
dis->ib = dis->ib<<18 & LT;
dis->ibc--;
dis->state = ST_DLY_IDP;
break;
case ST_DLY_IDP:
if(dis->move && dis->br&0200000)
intensify(dis);
dis->simtime += 500;
dis->state = ST_IDP;
break;
case ST_IDP:
dis->state = ST_IDLE;
switch(dis->mode) {
case PM:
// TODO: what is RI?
read_to_mode(dis);
/* PM PULSE */
if(dis->br & 010) dis->i = LDB(0, 3, dis->br);
if(dis->br & 0100) dis->sz = LDB(4, 2, dis->br);
if(dis->br & 02000) dis->stop = 1;
else dis->state = ST_RFD;
break;
case XYM:
if(dis->lp_flag)
break;
if(dis->br & 0200000){
// Y START
read_to_mode(dis);
dis->y = 0; // CLEAR Y
dis->simtime += 200;
dis->y |= dis->br & 01777; // LOAD Y
if(dis->br & 0002000)
dis->simtime += 35000;
}else{
// X START
read_to_mode(dis);
dis->simtime += 35000;
dis->x = 0; // CLEAR X
// 200ns parallel to above dly
dis->x |= dis->br & 01777; // LOAD X
}
dis->state = ST_XY_INTENSIFY;
break;
case IM:
halt = dis->halt;
count_brm(dis);
pnt = LDB(16, 4, dis->pnts);
r = (pnt & 014) == 010;
l = (pnt & 014) == 014;
u = (pnt & 003) == 002;
d = (pnt & 003) == 003;
goto count_xy;
case VM:
case VCM:
halt = dis->halt;
brm = dis->brm;
count_brm(dis);
/* actually the complement inputs to COUNT BRM
* but it's easier to find them out after the addition. */
c = dis->brm^brm;
getdir(brm, LDB(0, 8, dis->br), c, &r, &l);
getdir(brm, LDB(8, 8, dis->br), c, &u, &d);
count_xy:
count_y(dis, 1<<dis->sz, u, d);
count_x(dis, 1<<dis->sz, r, l);
if(halt) {
/* at COUNT X */
if(dis->br & 0400000)
escape(dis);
dis->state = ST_RFD;
} else {
// dly started by COUNT BRM
dis->simtime += 1000;
dis->state = ST_SEQ_DLY;
}
break;
case CM:
/* Tell CG to start */
dis->cp = chars[LDB(12, 6, dis->chrs) + dis->shift];
dis->state = ST_CHAR;
break;
}
break;
case ST_CHAR:
pnt = dis->pnt = *dis->cp++;
if(pnt == 0) {
end:
/* end of character */
if(dis->s & 1)
dis->state = ST_RFD;
else {
shift_s(dis);
dis->state = ST_DLY_IDP;
}
break;
}
if(pnt & 040) {
/* escape from char */
escape(dis);
dis->state = ST_RFD;
break;
}
if(pnt & 0100) {
/* carriage return */
dis->x = 0;
goto end; // maybe?
}
if(pnt & 0200) {
/* shift in */
dis->shift = 0;
goto end;
}
if(pnt & 0400) {
/* shift out */
dis->shift = 64;
goto end;
}
/* cg count */
r = (pnt & 014) == 010;
l = (pnt & 014) == 014;
u = (pnt & 003) == 002;
d = (pnt & 003) == 003;
count_y(dis, 1<<dis->sz, u, d);
count_x(dis, 1<<dis->sz, r, l);
dis->simtime += 1000;
dis->state = ST_CHAR_INT;
break;
case ST_CHAR_INT:
if(dis->pnt & 020)
intensify(dis);
dis->simtime += 500;
dis->state = ST_CHAR;
break;
case ST_SEQ_DLY:
dis->state = ST_IDLE;
if(dis->mode == VM && dis->brm == 0177)
dis->halt = 1;
if(dis->hef || dis->vef){
escape(dis);
if(dis->mode == VCM)
dis->state = ST_RFD;
}else if(!dis->rfd && !dis->lp_flag)
dis->state = ST_DLY_IDP;
break;
case ST_XY_INTENSIFY:
if(dis->br & 0002000)
intensify(dis);
dis->simtime += 500;
dis->state = ST_RFD;
break;
case ST_RFD:
rfd(dis);
dis->state = ST_IDLE;
break;
}
}
// could be more efficient with this
if(doreq) calc_dis_req(pdp, dis);
}
static void
handle_dis(PDP6 *pdp, IOdev *dev, int cmd)
{
Dis340 *dis = (Dis340*)dev->dev;
switch(cmd) {
case IOB_RESET:
dis->pia_data = 0;
dis->pia_spec = 0;
dis->ib = 0;
dis->ibc = 0;
initiate(dis);
break;
case IOB_CONO_CLR:
dis->pia_data = 0;
dis->pia_spec = 0;
return;
case IOB_CONO_SET:
// TODO: according to .INFO.;340 INFO more stuff:
// 24 clear no ink mode
// 25 set no ink mode
// 26 clear half word mode
// 27 set half word mode
// 28 resume display
dis->pia_data |= IOB & 7;
dis->pia_spec |= IOB>>3 & 7;
if(IOB & F29)
initiate(dis);
else
resume(dis); // not sure about this
break;
case IOB_DATAO_CLR:
dis->ib = 0;
dis->ibc = 0;
return;
case IOB_DATAO_SET:
dis->ib |= IOB;
dis->ibc = 2;
break;
case IOB_STATUS:
#if 0
// like this in the manual
if(dis->lp_flag) IOB |= F25;
if(dis->hef || dis->vef) IOB |= F26;
#else
// according to .INFO.;340 INFO
IOB |= dis->mode<<15;
// VECT CONT LP??
if(dis->vef) IOB |= F24;
if(dis->lp_flag) IOB |= F25;
if(dis->hef) IOB |= F26;
#endif
if(dis->stop && dis->br&01000) IOB |= F27;
if(dis->ibc == 0 && dis->rfd) IOB |= F28;
IOB |= (dis->pia_spec & 7) << 3;
IOB |= dis->pia_data & 7;
return;
case IOB_DATAI:
IOB |= dis->x;
IOB |= dis->y << 18;
return;
}
calc_dis_req(pdp, dis);
}
static Dis340 dis;
static IOdev dis_dev = { 0, 0130, &dis, handle_dis, cycle_dis };
static void
calc_dis_req(PDP6 *pdp, Dis340 *dis)
{
int data, spec;
u8 req_data, req_spec;
data = dis->ibc == 0 && dis->rfd;
spec = dis->lp_flag ||
dis->hef || dis->vef ||
dis->stop && dis->br&01000;
req_data = data ? 0200 >> dis->pia_data : 0;
req_spec = spec ? 0200 >> dis->pia_spec : 0;
setreq(pdp, &dis_dev, req_data | req_spec);
}
// stub
static void
handle_joy(PDP6 *pdp, IOdev *dev, int cmd)
{
switch(cmd) {
case IOB_DATAI:
IOB |= FW;
break;
}
}
static IOdev joy_dev = { 0, 0420, nil, handle_joy, nil };
Dis340*
attach_dis(PDP6 *pdp)
{
dis.fd = -1;
installdev(pdp, &dis_dev);
installdev(pdp, &joy_dev);
return &dis;
}
void
dis_connect(Dis340 *dis, int fd)
{
if(dis->fd >= 0)
close(dis->fd);
dis->fd = fd;
}

172
newemu/ge.c Normal file
View File

@@ -0,0 +1,172 @@
#include "common.h"
#include "pdp6.h"
#include <unistd.h>
#define IOB pdp->iob
typedef struct GEcon GEcon;
struct GEcon {
int out_pia;
bool out_ready;
bool out_busy;
u8 out_chr;
u8 out_lp;
int out_port;
int out_state;
u64 out_timer;
int in_pia;
bool in_ready;
u8 in_chr;
};
static void calc_ge_req(PDP6 *pdp, GEcon *ge);
static void
handle_gtyi(PDP6 *pdp, IOdev *dev, int cmd)
{
GEcon *ge = (GEcon*)dev->dev;
switch(cmd) {
case IOB_RESET:
case IOB_CONO_CLR:
ge->in_pia = 0;
ge->in_ready = 0;
break;
case IOB_CONO_SET:
ge->in_pia |= IOB & 7;
break;
case IOB_STATUS:
IOB |= ge->in_pia;
if(ge->in_ready) IOB |= F32;
return;
case IOB_DATAI:
IOB |= ge->in_chr;
ge->in_ready = 0;
break;
}
calc_ge_req(pdp, ge);
}
static void
handle_gtyo(PDP6 *pdp, IOdev *dev, int cmd)
{
GEcon *ge = (GEcon*)dev->dev;
switch(cmd) {
case IOB_RESET:
case IOB_CONO_CLR:
ge->out_pia = 0;
ge->out_ready = 0;
ge->out_busy = 0;
ge->out_chr = 0;
ge->out_state = 0;
break;
case IOB_CONO_SET:
ge->out_pia |= IOB & 7;
// init somehow
if(IOB & F28) {
ge->out_busy = 0;
ge->out_ready = 1;
}
break;
case IOB_DATAO_CLR:
ge->out_chr = 0;
ge->out_ready = 0;
ge->out_busy = 1;
break;
case IOB_DATAO_SET:
ge->out_chr |= (IOB & 0177)^0177;
ge->out_chr = (ge->out_chr<<1 | ge->out_chr>>6) & 0177;
ge->out_lp ^= ge->out_chr;
ge->out_timer = simtime + 1000000;
break;
case IOB_STATUS:
IOB |= ge->out_pia;
if(ge->out_ready) IOB |= F29;
return;
}
calc_ge_req(pdp, ge);
}
static void
cycle_ge(PDP6 *pdp, IOdev *dev, int pwr)
{
GEcon *ge = (GEcon*)dev->dev;
if(!pwr) {
return;
}
// TODO: actually connect this to consoles
if(ge->out_busy && ge->out_timer < simtime) {
switch(ge->out_state) {
case 0: // wait for msg start
if(ge->out_chr == 1) {
ge->out_state = 1;
ge->out_lp = 0;
}
break;
case 1: // read port to write to
if((ge->out_chr & 0147) == 0140) {
ge->out_state = 2;
ge->out_port = (ge->out_chr>>3) & 7;
} else
ge->out_state = 0;
break;
case 2: // read status code (always 0 for us)
if(ge->out_chr == 0)
ge->out_state = 3;
else
ge->out_state = 0;
break;
case 3: // read start of message
if(ge->out_chr == 2)
ge->out_state = 4;
break;
case 4: // the actual message
if(ge->out_chr == 3)
ge->out_state = 5;
else
printf("GE %d: %o\n", ge->out_port, ge->out_chr);
break;
case 5: // checksum
if(ge->out_lp != 0)
printf("GE checksum error %o\n", ge->out_lp);
ge->out_state = 0;
break;
}
ge->out_ready = 1;
ge->out_busy = 0;
calc_ge_req(pdp, ge);
}
}
static GEcon gecon;
static IOdev gtyi_dev = { 0, 0070, &gecon, handle_gtyi, nil };
static IOdev gtyo_dev = { 0, 0750, &gecon, handle_gtyo, cycle_ge };
static void
calc_ge_req(PDP6 *pdp, GEcon *ge)
{
int ireq = 0;
if(ge->in_pia && ge->in_ready)
ireq = 0200>>ge->in_pia;
setreq(pdp, &gtyi_dev, ireq);
int oreq = 0;
if(ge->out_pia && ge->out_ready)
oreq = 0200>>ge->out_pia;
setreq(pdp, &gtyo_dev, oreq);
}
void
attach_ge(PDP6 *pdp)
{
installdev(pdp, &gtyi_dev);
installdev(pdp, &gtyo_dev);
}

5486
newemu/instgen.inc Normal file

File diff suppressed because it is too large Load Diff

293
newemu/main.c Normal file
View File

@@ -0,0 +1,293 @@
#include "common.h"
#include "pdp6.h"
#include "args.h"
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
u64 simtime;
u64 realtime;
typedef struct Panel Panel;
void updateswitches(PDP6 *pdp, Panel *panel);
void updatelights(PDP6 *pdp, Panel *panel);
void lightsoff(Panel *panel);
Panel *getpanel(void);
// tmp
extern Word memory[01000000];
extern Word fmem[020];
#define I(op, ac, i, x, y)\
((Word)(op)<<27 |\
(Word)(ac)<<23 |\
(Word)(i)<<22 |\
(Word)(x)<<18 |\
(Word)(y))
#define IO(op, dev, i, x, y)\
((Word)(7)<<33 |\
(Word)(dev)<<24 |\
(Word)(op)<<23 |\
(Word)(i)<<22 |\
(Word)(x)<<18 |\
(Word)(y))
Hword
readmemory(const char *path)
{
char line[128], *p;
Hword a, pc;
Word d;
FILE *f;
f = fopen(path, "r");
if(f == NULL) {
printf("couldn't open file %s\n", path);
return 0;
}
pc = 0;
while(p = fgets(line, sizeof(line), f)) {
if(*p == 'd') {
p++;
sscanf(p, "%o %llo", &a, &d);
memory[a] = d;
} else if(*p == 'g') {
p++;
sscanf(p, "%o", &pc);
break;
}
}
fclose(f);
return pc;
}
const bool throttle = 1;
// TODO: this sucks
Dis340 *dis;
Ux555 *ux1;
Ux555 *ux2;
Ux555 *ux3;
Ux555 *ux4;
void
configmachine(PDP6 *pdp)
{
uxmount(ux1, "t/systemdis.dtr");
// uxmount(ux1, "t/system.dtr");
// uxmount(ux2, "t/syseng.dtr");
uxmount(ux2, "t/its138.dtr");
// uxmount(ux3, "t/foo.dtr");
uxmount(ux3, "t/music.dtr");
/* MACDMP RIM loader */
memory[000] = 0255000000000;
memory[001] = 0205000255000;
memory[002] = 0700200635550;
memory[003] = 0700600011577;
memory[004] = 0721200223110;
memory[005] = 0720200004010;
memory[006] = 0720340001000;
memory[007] = 0254000000006;
memory[010] = 0720040000013;
memory[011] = 0345540000006;
memory[012] = 0602540777777;
memory[013] = 0000000000013;
memory[014] = 0254000000006;
/* PTR RIM loader */
memory[020] = 0710600000060;
memory[021] = 0710740000010;
memory[022] = 0254000000021;
memory[023] = 0710440000026;
memory[024] = 0710740000010;
memory[025] = 0254000000024;
memory[027] = 0254000000021;
pdp->pc = 020;
// pdp->pc = readmemory("t/pdp6.part3.oct");
// part3: assumes non-existent memory at 777777 at PC=2004
// assumes reader motor will be off
// memory[0101] |= I(0, 1, 0, 0, 0); // disable device tests in part3
// part4: start with 1 in switches, flip back to 0 at some point
// pdp->pc = readmemory("t/ddt.16k.oct");
pdp->pc = readmemory("t/ddt.d16k.oct"); // needs moby
// pdp->pc = readmemory("t/nts.lisp.u16k.oct");
// pdp->pc = readmemory("t/nts.teco6.u256k.oct");
// pdp->pc = readmemory("t/spcwar.oct");
// pdp->pc = readmemory("t/hello.oct");
// pdp->pc = readmemory("t/its138.oct");
// pdp->pc = readmemory("t/music.oct");
}
int domusic = 0;
void
initemu(PDP6 *pdp)
{
memset(pdp, 0, sizeof(*pdp));
predecode();
initdevs(pdp);
attach_ptp(pdp);
attach_ptr(pdp);
attach_tty(pdp);
dis = attach_dis(pdp);
Dc136 *dc = attach_dc(pdp);
Ut551 *ut = attach_ut(pdp, dc);
ux1 = attach_ux(ut, 1);
ux2 = attach_ux(ut, 2);
ux3 = attach_ux(ut, 3);
ux4 = attach_ux(ut, 4);
// stub for ITS
attach_ge(pdp);
srand(time(NULL));
pwrclr(pdp);
cycle_io(pdp, 0);
if(domusic) initmusic();
}
void
emu(PDP6 *pdp, Panel *panel)
{
bool key_manual;
bool key_inst_stop;
bool power;
updateswitches(pdp, panel);
inittime();
simtime = 0; //gettime();
pdp->clk_timer = 0;
for(;;) {
key_manual = pdp->key_manual;
key_inst_stop = pdp->key_inst_stop;
power = pdp->sw_power;
updateswitches(pdp, panel);
if(pdp->sw_power) {
if(pdp->key_manual && !key_manual)
kt0(pdp);
if(pdp->key_inst_stop && !key_inst_stop) {
clr_run(pdp);
pdp->ia_inh = 1;
pdp->ia_inh_timer = simtime + 100000;
}
if(pdp->ia_inh && simtime > pdp->ia_inh_timer)
pdp->ia_inh = 0;
if(pdp->cycling) {
// avg: 1.4 - 1.7μs
cycle(pdp);
svc_music(pdp);
} else {
simtime += 1500; // keep things running
pdp->ia_inh = 0;
stopmusic();
}
updatelights(pdp, panel);
cycle_io(pdp, 1);
if(throttle) while(realtime < simtime) realtime = gettime();
} else {
stopmusic();
if(power)
pwrclr(pdp);
lightsoff(panel);
if(throttle)
simtime = gettime();
else
simtime += 1500;
cycle_io(pdp, 0);
}
// cli(pdp);
}
}
char *argv0;
void
usage(void)
{
fprintf(stderr, "usage: %s [-h host] [-p port]\n", argv0);
exit(1);
}
void
inthandler(int sig)
{
exit(0);
}
int
main(int argc, char *argv[])
{
Panel *panel;
PDP6 pdp6, *pdp = &pdp6;
const char *host;
int port;
host = "localhost";
port = 3400;
ARGBEGIN {
case 'h':
host = EARGF(usage());
break;
case 'p':
port = atoi(EARGF(usage()));
break;
default:
usage();
} ARGEND;
panel = getpanel();
if(panel == nil) {
fprintf(stderr, "can't find operator panel\n");
return 1;
}
atexit(exitcleanup);
signal(SIGPIPE, SIG_IGN);
signal(SIGINT, inthandler);
addcleanup((void (*)(void*))lightsoff, panel);
initemu(pdp);
configmachine(pdp);
int dis_fd = dial(host, port);
if(dis_fd < 0)
printf("can't open display\n");
nodelay(dis_fd);
dis_connect(dis, dis_fd);
// const char *tape = "t/hello.rim";
// const char *tape = "t/ptp_test.rim";
const char *tape = "t/bla.txt";
pdp->ptr_fd = open(tape, O_RDONLY);
pdp->ptp_fd = open("out.ptp", O_CREAT|O_WRONLY|O_TRUNC, 0644);
pdp->tty_fd = open("/tmp/tty", O_RDWR);
if(pdp->tty_fd < 0)
printf("can't open /tmp/tty\n");
emu(pdp, panel);
return 0; // can't happen
}

102
newemu/panel10.c Normal file
View File

@@ -0,0 +1,102 @@
#include "common.h"
#include "panel_pidp10.h"
#include "pdp6.h"
void
updateswitches(PDP6 *pdp, Panel *panel)
{
int sw3 = panel->sw3;
int sw4 = panel->sw4;
// TODO: make sure "opposite" keys are not down at the same time
pdp->key_start = !!(sw3 & KEY_START);
pdp->key_read_in = !!(sw3 & KEY_READIN);
pdp->key_dep = !!(sw3 & KEY_DEP);
pdp->key_dep_nxt = !!(sw3 & KEY_DEP_NEXT);
pdp->key_ex = !!(sw3 & KEY_EX);
pdp->key_ex_nxt = !!(sw3 & KEY_EX_NEXT);
pdp->key_io_reset = !!(sw3 & KEY_RESET);
pdp->key_execute = !!(sw3 & KEY_XCT) && !pdp->run;
pdp->key_mem_stop = !!(sw4 & SW_SING_CYC);
pdp->key_inst_stop = !!(sw4 & SW_SING_INST) || !!(sw3 & KEY_STOP);
pdp->sw_power = 1;
pdp->sw_mem_disable = !!(sw4 & SW_NXM_STOP);
pdp->sw_addr_stop = !!(sw4 & SW_ADR_STOP);
pdp->sw_repeat = !!(sw4 & SW_REPT);
pdp->datasw = panel->sw0 | (Word)panel->sw1<<18;
pdp->mas = panel->sw2;
if(pdp->mc_stop) {
pdp->key_inst_cont = 0;
pdp->key_mem_cont = !!(sw3 & KEY_CONT);
} else {
pdp->key_inst_cont = !!(sw3 & KEY_CONT);
pdp->key_mem_cont = 0;
}
// this sucks a bit
pdp->ptr_tape_feed = 0;
pdp->ptp_tape_feed = 0;
pdp->sw_ptr_motor_on = 0;
pdp->sw_ptr_motor_off = 0;
pdp->key_manual =
pdp->key_start ||
pdp->key_read_in ||
pdp->key_inst_cont ||
pdp->key_io_reset ||
pdp->key_execute ||
pdp->key_ex || pdp->key_ex_nxt ||
pdp->key_dep || pdp->key_dep_nxt;
pdp->dotrace = !!(sw4 & SW_PAR_STOP);
}
void
updatelights(PDP6 *pdp, Panel *panel)
{
int l;
panel->lights0 = pdp->mi & 0777777;
panel->lights1 = (pdp->mi>>18) & 0777777;
panel->lights2 = pdp->ma & 0777777;
panel->lights3 = pdp->ir & 0777777;
panel->lights4 = pdp->pc & 0777777;
l = pdp->pio;
l |= pdp->iob_req << 7;
l |= L5_POWER;
if(pdp->mc_stop)
l |= L5_MC_STOP;
if(pdp->ex_user)
l |= L5_USER_MODE;
panel->lights5 = l;
l = pdp->pir;
l |= pdp->pih << 7;
if(pdp->run)
l |= L6_RUN;
if(pdp->pi_on)
l |= L6_PI_ON;
panel->lights6 = l;
}
void
lightsoff(Panel *panel)
{
panel->lights0 = 0;
panel->lights1 = 0;
panel->lights2 = 0;
panel->lights3 = 0;
panel->lights4 = 0;
panel->lights5 = 0;
panel->lights6 = 0;
}
Panel*
getpanel(void)
{
return attachseg("/tmp/pdp10_panel", sizeof(Panel));
}

91
newemu/panel6.c Normal file
View File

@@ -0,0 +1,91 @@
#include "common.h"
#include "../panel/panel6.h"
#include "pdp6.h"
void
updateswitches(PDP6 *pdp, Panel6 *panel)
{
int sw3 = panel->sw3;
pdp->key_start = !!(sw3 & KEY_START);
pdp->key_read_in = !!(sw3 & KEY_READIN);
pdp->key_inst_cont = !!(sw3 & KEY_INST_CONT);
pdp->key_mem_cont = !!(sw3 & KEY_MEM_CONT);
pdp->key_inst_stop = !!(sw3 & KEY_INST_STOP);
pdp->key_mem_stop = !!(sw3 & KEY_MEM_STOP);
pdp->key_io_reset = !!(sw3 & KEY_IO_RESET);
pdp->key_execute = !!(sw3 & KEY_EXEC) && !pdp->run;
pdp->key_dep = !!(sw3 & KEY_DEP);
pdp->key_dep_nxt = !!(sw3 & KEY_DEP_NXT);
pdp->key_ex = !!(sw3 & KEY_EX);
pdp->key_ex_nxt = !!(sw3 & KEY_EX_NXT);
pdp->sw_power = !!(panel->sw3 & SW_POWER);
pdp->sw_mem_disable = !!(sw3 & SW_MEM_DISABLE);
pdp->sw_addr_stop = !!(sw3 & SW_ADDR_STOP);
pdp->sw_repeat = !!(sw3 & SW_REPEAT);
pdp->datasw = panel->sw0 | (Word)panel->sw1<<18;
pdp->mas = panel->sw2;
pdp->ptr_tape_feed = !!(panel->sw4 & KEY_PTR_FEED);
pdp->ptp_tape_feed = !!(panel->sw4 & KEY_PTP_FEED);
pdp->sw_ptr_motor_on = !!(panel->sw4 & KEY_MOTOR_ON);
pdp->sw_ptr_motor_off = !!(panel->sw4 & KEY_MOTOR_OFF);
pdp->key_manual =
pdp->key_start ||
pdp->key_read_in ||
pdp->key_inst_cont ||
pdp->key_io_reset ||
pdp->key_execute ||
pdp->key_ex || pdp->key_ex_nxt ||
pdp->key_dep || pdp->key_dep_nxt;
pdp->dotrace = 0;
}
void
updatelights(PDP6 *pdp, Panel6 *panel)
{
int l;
panel->lights0 = pdp->mi & 0777777;
panel->lights1 = (pdp->mi>>18) & 0777777;
panel->lights2 = pdp->ma & 0777777;
panel->lights3 = pdp->ir & 0777777;
panel->lights4 = pdp->pc & 0777777;
l = pdp->pio;
if(pdp->run) l |= L5_RUN;
if(pdp->pi_on) l |= L5_PI_ON;
if(pdp->mc_stop) l |= L5_MC_STOP;
if(pdp->sw_mem_disable) l |= L5_MEM_DISABLE;
if(pdp->sw_addr_stop) l |= L5_ADDR_STOP;
if(pdp->sw_repeat) l |= L5_REPEAT;
l |= L5_POWER;
panel->lights5 = l;
l = pdp->pir;
l |= pdp->pih<<7;
panel->lights6 = l;
}
void
lightsoff(Panel6 *panel)
{
panel->lights0 = 0;
panel->lights1 = 0;
panel->lights2 = 0;
panel->lights3 = 0;
panel->lights4 = 0;
panel->lights5 = 0;
panel->lights6 = 0;
}
Panel6*
getpanel(void)
{
return attachseg("/tmp/pdp6_panel", sizeof(Panel6));
}

2776
newemu/pdp6.c Normal file

File diff suppressed because it is too large Load Diff

323
newemu/pdp6.h Normal file
View File

@@ -0,0 +1,323 @@
#include <stdbool.h>
typedef u64 Word;
typedef u32 Hword;
typedef struct PDP6 PDP6;
void addcleanup(void (*func)(void*), void *arg);
void exitcleanup(void);
#define F0 0400000000000
#define F1 0200000000000
#define F2 0100000000000
#define F3 0040000000000
#define F4 0020000000000
#define F5 0010000000000
#define F6 0004000000000
#define F7 0002000000000
#define F8 0001000000000
#define F9 0000400000000
#define F10 0000200000000
#define F11 0000100000000
#define F12 0000040000000
#define F13 0000020000000
#define F14 0000010000000
#define F15 0000004000000
#define F16 0000002000000
#define F17 0000001000000
#define F18 0000000400000
#define F19 0000000200000
#define F20 0000000100000
#define F21 0000000040000
#define F22 0000000020000
#define F23 0000000010000
#define F24 0000000004000
#define F25 0000000002000
#define F26 0000000001000
#define F27 0000000000400
#define F28 0000000000200
#define F29 0000000000100
#define F30 0000000000040
#define F31 0000000000020
#define F32 0000000000010
#define F33 0000000000004
#define F34 0000000000002
#define F35 0000000000001
#define LT 0777777000000
#define RT 0777777
#define FW 0777777777777
typedef u32 Code;
struct PDP6
{
int cycling;
int state, estate;
Code code;
bool key_start;
bool key_read_in;
bool key_mem_stop;
bool key_mem_cont;
bool key_inst_stop;
bool key_inst_cont;
bool key_ex;
bool key_ex_nxt;
bool key_dep;
bool key_dep_nxt;
bool key_io_reset;
bool key_execute;
bool key_manual; // for convenience
bool sw_power;
bool sw_mem_disable;
bool sw_addr_stop;
bool sw_repeat;
bool run;
bool key_rim_sbr;
bool mc_stop;
bool key_ex_st;
bool key_dep_st;
bool key_ex_sync;
bool key_dep_sync;
Word ar;
Word mq;
u8 mq36;
Word mb;
Word mi;
Word datasw;
Hword pc;
Hword ma;
Hword mas;
Hword ir;
Hword fe, sc; // 9 bits
Word iob;
u8 iob_req;
// SBR flip flops
// memory
bool key_rd_wr;
bool if1a;
bool af0, af3;
bool f1a, f4a, f6a;
bool sf3, sf5a, sf7;
bool uuo_f1;
bool blt_f0a;
bool iot_f0a;
bool chf6;
// AR
bool ar_com_cont;
bool af3a;
bool et4_ar_pause;
bool chf3;
bool blt_f3a, blt_f5a;
bool faf4;
bool msf1;
bool nrf1;
bool dsf1, dsf2, dsf3, dsf4, dsf5, dsf6, dsf8, dsf9;
// shift count
bool shf1;
bool chf4, lcf1, dcf1, faf3;
// SC add
bool chf2;
bool fsf1;
bool faf2;
bool fpf1, fpf2;
// exponent
bool fmf1;
bool fdf1;
// multiply
bool mpf1;
bool fmf2;
// divide
bool fdf2;
// misc FFs
bool faf1; // SC PAD enable
bool chf1; // SC PAD enable
bool nrf2; // ASHC enable
bool nrf3; // NR ROUND disable
bool dsf7; // division sign flag
bool mpf2; // multiply sign flag
bool iot_go;
// char state
bool chf5, chf7;
bool pi_active;
bool pi_cyc, pi_ov;
bool pi_on;
u8 pio, pir, pih, pi_req;
bool ex_user;
bool ex_mode_sync;
bool ex_pi_sync;
bool ex_uuo_sync;
bool ex_ill_op;
Hword pr, rlr, rla;
bool mc_rq, mc_rd, mc_wr;
bool cpa_iot_user;
bool cpa_illeg_op;
bool cpa_non_exist_mem;
bool cpa_clock_enable;
bool cpa_clock_flag;
bool cpa_pc_chg_enable;
bool cpa_pdl_ov;
bool cpa_arov_enable;
u8 cpa_pia;
bool ar_cry0, ar_cry1;
bool ar_cry0_flag, ar_cry1_flag;
bool ar_ov_flag;
bool ar_pc_chg_flag;
/* PTP */
bool sw_ptr_motor_on;
bool sw_ptr_motor_off;
bool ptp_tape_feed;
bool ptp_motor_on;
bool ptp_busy;
bool ptp_flag;
bool ptp_b;
u8 ptp;
int ptp_pia;
int ptp_fd;
u64 ptp_punch_timer;
u64 ptp_motor_off_timer;
u64 ptp_motor_on_timer;
/* PTR */
bool ptr_tape_feed;
bool ptr_motor_on;
bool ptr_clutch;
u8 ptr_sr;
Word ptr;
bool ptr_busy;
bool ptr_flag;
bool ptr_b;
int ptr_pia;
int ptr_fd;
u64 ptr_timer;
/* TTY */
u8 tty_pia;
bool tto_busy;
bool tto_flag;
bool tto_active;
u8 tto;
bool tti_busy;
bool tti_flag;
u8 tti;
//
int tty_baud, tty_dly;
int tty_fd;
int tti_state;
u64 tti_timer;
u64 tto_timer;
bool dotrace;
u64 clk_timer;
/* temp - for time measurement */
u64 sim_start, sim_end;
u64 real_start, real_end;
bool ia_inh;
u64 ia_inh_timer;
};
void predecode(void);
void pwrclr(PDP6 *pdp);
void kt0(PDP6 *pdp);
void cycle(PDP6 *pdp);
void clr_run(PDP6 *pdp);
extern u64 simtime;
extern u64 realtime;
enum {
IOB_CONO_CLR,
IOB_CONO_SET,
IOB_DATAO_CLR,
IOB_DATAO_SET,
IOB_DATAI,
IOB_STATUS,
IOB_RESET
};
typedef struct IOdev IOdev;
struct IOdev {
u8 req;
int devcode;
void *dev;
void (*handler)(PDP6 *pdp, IOdev *dev, int cmd);
void (*cycle)(PDP6 *pdp, IOdev *dev, int pwr);
};
void initdevs(PDP6 *pdp);
void installdev(PDP6 *pdp, IOdev *dev);
void cycle_io(PDP6 *pdp, int pwr);
void setreq(PDP6 *pdp, IOdev *dev, u8 req);
void attach_ptp(PDP6 *pdp);
void ptr_set_motor(PDP6 *pdp, int state);
void attach_ptr(PDP6 *pdp);
void attach_tty(PDP6 *pdp);
typedef struct Dis340 Dis340;
Dis340 *attach_dis(PDP6 *pdp);
void dis_connect(Dis340 *dis, int fd);
typedef struct Dc136 Dc136;
struct Dc136
{
PDP6 *pdp;
int pia;
int device;
int ch_mode;
Word da;
Word db;
int cct;
int sct;
bool data_clbd;
bool dbda_move;
bool darq;
bool dbrq;
bool inout;
};
Dc136 *attach_dc(PDP6 *pdp);
int dctkgv(Dc136 *dc, int dev, int ch, int rt);
typedef struct Ux555 Ux555;
typedef struct Ut551 Ut551;
Ut551 *attach_ut(PDP6 *pdp, Dc136 *dc);
Ux555 *attach_ux(Ut551 *ut, int num);
void uxmount(Ux555 *ux, const char *path);
void uxunmount(Ux555 *ux);
void attach_ge(PDP6 *pdp);
void initmusic(void);
void stopmusic(void);
void svc_music(PDP6 *pdp);

266
newemu/pt.c Normal file
View File

@@ -0,0 +1,266 @@
#include "common.h"
#include "pdp6.h"
#include <unistd.h>
#define IOB pdp->iob
#define PTP_DLY 15797788 // 63.3 chars per second
#define PTR_DLY 2500000 // 400 chars per second
/* PTP */
static void calc_ptp_req(PDP6 *pdp);
static void
handle_ptp(PDP6 *pdp, IOdev *dev, int cmd)
{
switch(cmd) {
case IOB_RESET:
case IOB_CONO_CLR:
pdp->ptp_b = 0;
pdp->ptp_busy = 0;
pdp->ptp_flag = 0;
pdp->ptp_pia = 0;
break;
case IOB_CONO_SET:
if(IOB & F30) pdp->ptp_b = 1;
if(IOB & F31) pdp->ptp_busy = 1;
if(IOB & F32) pdp->ptp_flag = 1;
pdp->ptp_pia |= IOB & 7;
break;
case IOB_STATUS:
if(pdp->ptp_b) IOB |= F30;
if(pdp->ptp_busy) IOB |= F31;
if(pdp->ptp_flag) IOB |= F32;
IOB |= pdp->ptp_pia;
return;
case IOB_DATAO_CLR:
pdp->ptp_busy = 1;
pdp->ptp_flag = 0;
pdp->ptp = 0;
return;
case IOB_DATAO_SET:
pdp->ptp |= IOB & 0377;
break;
}
calc_ptp_req(pdp);
}
static void
ptp_set_motor(PDP6 *pdp, int state)
{
if(pdp->ptp_motor_on == state)
return;
pdp->ptp_motor_on = state;
if(!pdp->ptp_motor_on)
pdp->ptp_motor_on_timer = NEVER;
else
pdp->ptp_punch_timer = simtime + PTP_DLY;
}
static void
cycle_ptp(PDP6 *pdp, IOdev *dev, int pwr)
{
u8 c;
bool go;
if(!pwr) {
pdp->ptp_motor_on = 0;
pdp->ptp_motor_on_timer = NEVER;
return;
}
go = pdp->ptp_busy || pdp->ptp_tape_feed;
if(go) {
pdp->ptp_motor_off_timer = simtime + 5000000000;
if(pdp->ptp_motor_on_timer == NEVER)
pdp->ptp_motor_on_timer = simtime + 1000000000;
}
if(!pdp->ptp_motor_on && pdp->ptp_motor_on_timer < simtime)
ptp_set_motor(pdp, 1);
if(pdp->ptp_motor_off_timer < simtime)
ptp_set_motor(pdp, 0);
if(!pdp->ptp_motor_on)
return;
if(pdp->ptp_punch_timer < simtime) {
// reluctance pickup
pdp->ptp_punch_timer = simtime + PTP_DLY;
if(pdp->ptp_busy) // PTP READY
c = (pdp->ptp_b ? pdp->ptp&077|0200 : pdp->ptp);
else if(pdp->ptp_tape_feed)
c = 0;
else
return;
if(pdp->ptp_fd >= 0)
if(write(pdp->ptp_fd, &c, 1) <= 0) {
close(pdp->ptp_fd);
pdp->ptp_fd = -1;
}
// PTP DONE
if(pdp->ptp_busy) {
pdp->ptp_busy = 0;
pdp->ptp_flag = 1;
calc_ptp_req(pdp);
}
}
}
static IOdev ptp_dev = { 0, 0100, handle_ptp, cycle_ptp };
static void
calc_ptp_req(PDP6 *pdp)
{
if(pdp->ptp_pia && pdp->ptp_flag)
setreq(pdp, &ptp_dev, 0200>>pdp->ptp_pia);
else
setreq(pdp, &ptp_dev, 0);
}
void
attach_ptp(PDP6 *pdp)
{
installdev(pdp, &ptp_dev);
}
/* PTR */
static void calc_ptr_req(PDP6 *pdp);
void
ptr_set_motor(PDP6 *pdp, int state)
{
if(pdp->ptr_motor_on == state)
return;
pdp->ptr_motor_on = state;
if(pdp->ptr_motor_on)
pdp->ptr_busy = 0;
pdp->ptr_flag = 1;
calc_ptr_req(pdp);
}
static void
ptr_set_busy(PDP6 *pdp)
{
if(!pdp->ptr_busy) {
// PTR CLR
pdp->ptr_sr = 0;
pdp->ptr = 0;
}
pdp->ptr_busy = 1;
}
static void
handle_ptr(PDP6 *pdp, IOdev *dev, int cmd)
{
switch(cmd) {
case IOB_RESET:
// hack for easier use. NB: this breaks diagnostics
ptr_set_motor(pdp, 1);
case IOB_CONO_CLR:
pdp->ptr_b = 0;
pdp->ptr_busy = 0;
pdp->ptr_flag = 0;
pdp->ptr_pia = 0;
break;
case IOB_CONO_SET:
if(IOB & F27) ptr_set_motor(pdp, 1); // not in schematics, can we turn it off too?
if(IOB & F30) pdp->ptr_b = 1;
if(IOB & F31) ptr_set_busy(pdp);
if(IOB & F32) pdp->ptr_flag = 1;
pdp->ptr_pia |= IOB & 7;
break;
case IOB_STATUS:
if(pdp->ptr_motor_on) IOB |= F27;
if(pdp->ptr_b) IOB |= F30;
if(pdp->ptr_busy) IOB |= F31;
if(pdp->ptr_flag) IOB |= F32;
IOB |= pdp->ptr_pia;
return;
case IOB_DATAI:
IOB |= pdp->ptr;
pdp->ptr_flag = 0;
// actually after DATAI negated
ptr_set_busy(pdp);
break;
}
calc_ptr_req(pdp);
}
static void
cycle_ptr(PDP6 *pdp, IOdev *dev, int pwr)
{
bool clutch;
u8 c;
if(!pwr) return;
if(pdp->sw_ptr_motor_on) ptr_set_motor(pdp, 1);
if(pdp->sw_ptr_motor_off) ptr_set_motor(pdp, 0);
clutch = pdp->ptr_motor_on && (pdp->ptr_busy | pdp->ptr_tape_feed);
if(clutch && !pdp->ptr_clutch) {
// start motion
pdp->ptr_timer = simtime + PTR_DLY;
}
pdp->ptr_clutch = clutch;
if(!pdp->ptr_clutch || pdp->ptr_timer >= simtime)
return;
pdp->ptr_timer = simtime + PTR_DLY;
if(!hasinput(pdp->ptr_fd))
return;
if(read(pdp->ptr_fd, &c, 1) <= 0) {
close(pdp->ptr_fd);
pdp->ptr_fd = -1;
return;
}
if(pdp->ptr_busy && (c & 0200 || !pdp->ptr_b)) {
// PTR STROBE
// actually 400μs after feed hole edge
pdp->ptr_sr = (pdp->ptr_sr<<1) | 1;
pdp->ptr <<= 6;
if(pdp->ptr_b)
pdp->ptr |= c & 077;
else
pdp->ptr |= c;
// PTR TRAIL
// only if busy but that's guaranteed here
if(!pdp->ptr_b || pdp->ptr_sr & 040) {
pdp->ptr_busy = 0;
pdp->ptr_flag = 1;
calc_ptr_req(pdp);
}
}
}
static IOdev ptr_dev = { 0, 0104, nil, handle_ptr, cycle_ptr };
static void
calc_ptr_req(PDP6 *pdp)
{
if(pdp->ptr_pia && pdp->ptr_flag)
setreq(pdp, &ptr_dev, 0200>>pdp->ptr_pia);
else
setreq(pdp, &ptr_dev, 0);
}
void
attach_ptr(PDP6 *pdp)
{
installdev(pdp, &ptr_dev);
}

134
newemu/tty.c Normal file
View File

@@ -0,0 +1,134 @@
#include "common.h"
#include "pdp6.h"
#include <unistd.h>
#define IOB pdp->iob
static void calc_tty_req(PDP6 *pdp);
static void
handle_tty(PDP6 *pdp, IOdev *dev, int cmd)
{
switch(cmd) {
case IOB_RESET:
pdp->tty_pia = 0;
pdp->tto_busy = 0;
pdp->tto_flag = 0;
pdp->tti_busy = 0;
pdp->tti_flag = 0;
pdp->tti_timer = 0;
break;
case IOB_CONO_CLR:
pdp->tty_pia = 0;
return;
case IOB_CONO_SET:
pdp->tty_pia |= IOB & 7;
if(IOB & F32) pdp->tto_flag = 1;
if(IOB & F31) pdp->tto_busy = 1;
if(IOB & F30) pdp->tti_flag = 1;
if(IOB & F29) pdp->tti_busy = 1;
if(IOB & F28) pdp->tto_flag = 0;
if(IOB & F27) pdp->tto_busy = 0;
if(IOB & F26) pdp->tti_flag = 0;
if(IOB & F25) pdp->tti_busy = 0;
break;
case IOB_DATAO_CLR:
pdp->tto_busy = 1;
pdp->tto_flag = 0;
break;
case IOB_DATAO_SET:
pdp->tto |= IOB & 0377;
pdp->tto_active = 1; // not really, but close enough
pdp->tto_timer = simtime + pdp->tty_dly*11;
break;
case IOB_DATAI:
pdp->tti_flag = 0;
IOB |= pdp->tti;
break;
case IOB_STATUS:
IOB |= pdp->tty_pia;
if(pdp->tto_flag) IOB |= F32;
if(pdp->tto_busy) IOB |= F31;
if(pdp->tti_flag) IOB |= F30;
if(pdp->tti_busy) IOB |= F29;
return;
}
calc_tty_req(pdp);
}
static void
cycle_tty(PDP6 *pdp, IOdev *dev, int pwr)
{
if(!pwr) {
pdp->tto_active = 0;
pdp->tti_state = 0;
return;
}
if(pdp->tto_active && pdp->tto_timer < simtime) {
pdp->tto_active = 0;
if(pdp->tty_fd >= 0) {
char c = pdp->tto & 0177;
write(pdp->tty_fd, &c, 1);
}
pdp->tto = 0;
pdp->tto_busy = 0;
pdp->tto_flag = 1;
calc_tty_req(pdp);
}
// timing is awkward right now, we think in bit-times
// 11 bits per char (start, 8 bit chars, 2 stop)
// t=0 read char
// t=9 set flag (simulate reading done)
// t=11 ready to accept next char
if(pdp->tti_timer < simtime) {
pdp->tti_timer = simtime + pdp->tty_dly;
if(pdp->tti_state == 0) {
if(hasinput(pdp->tty_fd)) {
char c;
if(read(pdp->tty_fd, &c, 1) <= 0) {
close(pdp->tty_fd);
pdp->tty_fd = -1;
return;
}
pdp->tti = c;
pdp->tti_busy = 1;
pdp->tti_flag = 0;
calc_tty_req(pdp);
pdp->tti_timer += pdp->tty_dly*8;
pdp->tti_state = 1;
}
} else {
if(pdp->tti_busy) {
pdp->tti_busy = 0;
pdp->tti_flag = 1;
calc_tty_req(pdp);
pdp->tti_timer += pdp->tty_dly;
pdp->tti_state = 0;
}
}
}
}
static IOdev tty_dev = { 0, 0120, nil, handle_tty, cycle_tty };
static void
calc_tty_req(PDP6 *pdp)
{
if(pdp->tty_pia && (pdp->tti_flag || pdp->tto_flag))
setreq(pdp, &tty_dev, 0200>>pdp->tty_pia);
else
setreq(pdp, &tty_dev, 0);
}
void
attach_tty(PDP6 *pdp)
{
pdp->tty_baud = 110;
pdp->tty_dly = 1000000000 / pdp->tty_baud;
installdev(pdp, &tty_dev);
}

616
newemu/ut.c Normal file
View File

@@ -0,0 +1,616 @@
#include "common.h"
#include "pdp6.h"
#include <fcntl.h>
#include <unistd.h>
#define MOVEDLY 33333
// very approximate, unfortunately no hard data for this
#define STARTDLY 200000000
#define STOPDLY 100000000 // not sure how to use this one here
#define TURNDLY 250000000
// ~350 lines per inch, ~4.56in per block
// again very approximate
#define STARTDIST 7*350
#define STOPDIST 8*350
// after turnaround we will have passed the location that we turned at
// TENDMP assumes one block of turnaround space
// MACDMP assumes two
#define TURNDIST 2*350
struct Ux555
{
int fd;
u8 *buf;
int size, pos;
bool written;
bool flapping;
u64 timer;
bool tp;
bool wrlock;
int num; // 0-7
// from controller:
int go;
int rev;
};
struct Ut551
{
Dc136 *dc;
int dcdev;
Ux555 *transports[8];
Ux555 *sel;
bool btm_sw;
bool units_select;
bool tape_end_en;
bool jb_done_en;
bool go;
bool rev;
bool time_en;
int time;
int fcn;
int units;
int pia;
bool incomp_block;
bool wren;
bool time_flag;
bool info_error;
bool illegal_op;
bool tape_end_flag;
bool jb_done_flag;
int utek;
bool uteck;
int lb;
int rwb;
int wb;
int tbm;
int tdata;
int tmk;
int tct;
int ramp; // read amplifiers
int state;
bool start_dly;
u64 dlyend;
};
Ux555*
attach_ux(Ut551 *ut, int num)
{
int i;
Ux555 *ux = malloc(sizeof(Ux555));
ux->fd = -1;
ux->buf = nil;
ux->size = 0;
ux->pos = 0;
ux->tp = 0;
ux->wrlock = 0;
ux->num = num & 7;
ux->go = 0;
ux->rev = 0;
for(i = 0; i < 8; i++)
if(ut->transports[i] == nil) {
ut->transports[i] = ux;
break;
}
addcleanup((void (*)(void*))uxunmount, ux);
return ux;
}
void
uxunmount(Ux555 *ux)
{
if(ux->fd < 0)
return;
if(ux->written) {
lseek(ux->fd, 0, SEEK_SET);
write(ux->fd, ux->buf, ux->size);
}
close(ux->fd);
ux->fd = -1;
free(ux->buf);
ux->buf = nil;
}
void
uxmount(Ux555 *ux, const char *path)
{
uxunmount(ux);
ux->fd = open(path, O_RDWR);
if(ux->fd < 0) {
ux->fd = open(path, O_RDONLY);
if(ux->fd < 0) {
fprintf(stderr, "can't open file <%s>\n", path);
return;
}
ux->wrlock = 1;
}
ux->size = lseek(ux->fd, 0, SEEK_END);
ux->buf = malloc(ux->size);
lseek(ux->fd, 0, SEEK_SET);
read(ux->fd, ux->buf, ux->size);
ux->written = 0;
ux->pos = 100;
ux->flapping = ux->pos >= ux->size; // hopefully always true
ux->tp = 0;
ux->go = 0;
ux->rev = 0;
printf("μt unit %d file <%s>, len %d lock? %d\n", ux->num, path, ux->size, ux->wrlock);
}
static void
uxmove(Ux555 *ux)
{
if(!ux->go || ux->timer >= simtime)
return;
ux->timer += MOVEDLY;
if(ux->rev) {
if(--ux->pos < 0)
//printf("flap back\n"),
ux->flapping = 1;
} else {
if(++ux->pos >= ux->size)
//printf("flap fwd\n"),
ux->flapping = 1;
}
if(!ux->flapping)
ux->tp = 1;
}
static void
uxsetmotion(Ux555 *ux, int go, int rev)
{
if(ux->go != go) {
if(!ux->go) {
//printf("start transport\n");
// start transport
ux->timer = simtime + STARTDLY;
ux->pos += rev ? -STARTDIST : STARTDIST;
} else {
// stop transport
//printf("stop transport\n");
ux->pos += ux->rev ? -STOPDIST : STOPDIST;
}
ux->go = go;
} else if(ux->go && ux->rev != rev) {
//printf("turn transport\n");
// turn around transport
ux->timer = simtime + TURNDLY;
ux->pos += rev ? -TURNDIST : TURNDIST;
}
ux->rev = rev;
}
#define IOB pdp->iob
enum {
RW_NULL,
RW_RQ,
RW_ACTIVE,
};
#define UT_DN (ut->fcn == 0)
#define UT_RDA (ut->fcn == 1)
#define UT_RDBM (ut->fcn == 2)
#define UT_RDD (ut->fcn == 3)
#define UT_WRTM (ut->fcn == 4)
#define UT_WRA (ut->fcn == 5)
#define UT_WRBM (ut->fcn == 6)
#define UT_WRD (ut->fcn == 7)
#define UT_WRITE (ut->fcn & 4)
#define UT_READ !UT_WRITE
#define UT_ALL (UT_RDA || UT_WRA)
#define UT_BM (UT_RDBM || UT_WRBM)
#define UT_DATA (UT_RDD || UT_WRD)
#define MK_BM_SPACE ((ut->tmk & 0477) == 0425)
#define MK_BM_SYNC (ut->tmk == 0751)
#define MK_DATA_SYNC (ut->tmk == 0632)
#define MK_BM_END (ut->tmk == 0526)
#define MK_FWD_DATA_END (ut->tmk == 0773 || ut->tmk == 0473)
#define MK_REV_DATA_END (ut->tmk == 0610 || ut->tmk == 0410)
#define MK_END (ut->tmk == 0622)
#define MK_DATA (ut->tmk == 0470)
#define MK_DATA_END (MK_FWD_DATA_END || MK_REV_DATA_END)
#define UTE_DC_DISCONNECT (ut->dc->darq || ut->dc->device != ut->dcdev)
#define UTE_MK (MK_BM_END || MK_BM_SYNC || MK_DATA_END || MK_DATA_SYNC || MK_DATA)
static void calc_ut_req(PDP6 *pdp, Ut551 *ut);
static int
utsel(Ut551 *ut)
{
int i, num, nsel;
num = ut->units;
// weirdness: ~UNITS SELECT only disables 0 and 1
if(!ut->units_select && num < 2)
num = -1;
nsel = 0;
ut->sel = nil;
for(i = 0; i < 8; i++)
if(ut->transports[i] && ut->transports[i]->num == num) {
ut->sel = ut->transports[i];
nsel++;
}
if(nsel != 1)
ut->sel = nil;
return nsel;
}
static void
tp0(Ut551 *ut)
{
Ux555 *ux = ut->sel;
if(ut->state == RW_ACTIVE) {
ut->wren = 1;
if(UT_WRITE) {
// RWB(J)->WB
ut->wb = (ut->rwb >> (ut->tct?0:3))&7;
if(ut->rev) ut->wb ^= 7;
if(ux->wrlock)
ut->illegal_op = 1;
}
}
}
static void
tp1(Ut551 *ut)
{
// write complement - rather useless for us here
if(UT_WRITE)
ut->wb ^= 7;
// advance TMK
if(!ut->start_dly && !UT_WRTM)
ut->tmk = ((ut->tmk<<1) | (ut->ramp>>3)&1)&0777 | ut->tmk&0400;
// strobe data into RWB
if(ut->state == RW_ACTIVE && UT_READ) {
int c = ut->rev && !UT_RDBM ? 7 : 0;
if(ut->tct)
ut->rwb |= ut->ramp&7 ^ c;
else
ut->rwb |= (ut->ramp&7 ^ c) << 3;
}
}
static void
tp2(Ut551 *ut)
{
bool wasdone = ut->jb_done_flag;
if(ut->state == RW_ACTIVE) {
if(ut->tct) {
// RW EVEN
ut->lb ^= ~ut->rwb & 077;
if(UT_READ && (ut->tdata&0102)==0) {
// RWB<->DC
ut->rwb |= dctkgv(ut->dc, ut->dcdev, ut->rwb, ut->rev && !UT_RDBM);
if(UTE_DC_DISCONNECT)
ut->incomp_block = 1;
}
}
ut->tct ^= 1;
if(UT_BM && MK_BM_END)
ut->jb_done_flag = 1;
if(!UT_ALL && (MK_BM_SYNC || MK_DATA_SYNC)) {
ut->info_error = 1;
ut->state = RW_NULL;
}
} else
ut->tct = 0;
if(ut->uteck && UTE_MK != (ut->utek==040))
ut->info_error = 1;
if(!MK_BM_SPACE)
ut->utek = (ut->utek>>1) | (ut->utek&1)<<5;
// only interested in rising edges here
int tbmedge = ~ut->tbm;
if(MK_BM_SYNC) ut->tbm = 010 | ut->tbm>>1;
else if(MK_BM_SPACE) ut->tbm >>= 1;
tbmedge &= ut->tbm;
// need both rising and falling edges
int tdedge = ut->tdata;
if(MK_DATA_SYNC) ut->tdata = 0200 | ut->tdata>>1;
else if(MK_DATA_END) ut->tdata >>= 1;
tdedge ^= ut->tdata;
if(tdedge & ut->tdata & 0100)
ut->lb = 0;
if(ut->state == RW_RQ) {
if(UT_BM && tbmedge & 1 ||
UT_ALL && tbmedge & 010 ||
UT_DATA && tdedge & ut->tdata & 0100)
ut->state = RW_ACTIVE;
} else if(ut->state == RW_ACTIVE && UT_DATA && (tdedge & ~ut->tdata & 2)) {
if(UTE_DC_DISCONNECT)
ut->jb_done_flag = 1;
else
ut->state = RW_RQ;
}
if(ut->jb_done_flag && !wasdone)
ut->state = RW_NULL;
}
static void
tp3(Ut551 *ut)
{
if(ut->state == RW_ACTIVE && !ut->tct)
ut->rwb = 0;
if(UT_READ && (UT_ALL | UT_DATA) && ut->tdata & 1 &&
ut->lb != 077)
ut->info_error = 1;
if(ut->tbm & 1) {
if(MK_BM_SPACE)
ut->utek = 040;
else
ut->uteck = 1;
}
if(MK_BM_SYNC)
ut->uteck = 0;
if(MK_END) {
ut->tape_end_flag = 1;
ut->state = RW_NULL;
}
}
static void
tp4(Ut551 *ut)
{
if(ut->state != RW_ACTIVE)
ut->wren = 0;
else if(!ut->tct) {
if(UT_WRITE && UT_DATA && ut->tdata & 2)
ut->rwb |= ut->lb;
if(UT_WRITE && (ut->tdata&0102)==0 || UT_WRTM) {
// RWB<->DC
// writing - so no need to check RDBM
ut->rwb |= dctkgv(ut->dc, ut->dcdev, ut->rwb, ut->rev);
if(UTE_DC_DISCONNECT)
ut->incomp_block = 1;
}
}
}
static void
cycle_ut(PDP6 *pdp, IOdev *dev, int pwr)
{
int i;
Ut551 *ut = (Ut551*)dev->dev;
Ux555 *ux;
if(!pwr) {
ut->dlyend = NEVER;
return;
}
int doreq = 0;
if(ut->start_dly && ut->dlyend < simtime) {
//printf("delay done\n");
ut->dlyend = NEVER;
ut->start_dly = 0;
ut->time_flag = 1;
if(utsel(ut) != 1) {
ut->go = 0;
ut->illegal_op = 1;
}
if(UT_WRTM != ut->btm_sw)
ut->illegal_op = 1;
if(UT_WRTM)
ut->state = RW_ACTIVE;
else if(!UT_DN)
ut->state = RW_RQ;
doreq = 1;
}
if(ut->tape_end_flag)
ut->go = 0;
// move transports
ux = ut->sel;
if(ux)
uxsetmotion(ux, ut->go, ut->rev);
for(i = 0; i < 8; i++)
if(ut->transports[i])
uxmove(ut->transports[i]);
if(ux && ux->tp) {
ux->tp = 0;
doreq = 1;
// rising edge of time track
int mask = ux->rev ? 017 : 0;
ut->ramp = ux->buf[ux->pos] ^ mask;
// which fires TP0 - write load
tp0(ut);
// write back at some point
if(UT_WRITE && ut->wren && !ux->wrlock) {
if(UT_WRTM && ut->btm_sw)
ux->buf[ux->pos] = ((ut->wb<<1)&010 | ut->wb) ^ mask;
else
ux->buf[ux->pos] = (ut->ramp&010 | ut->wb) ^ mask;
ux->written = 1;
}
// ca 16.6μs later
// falling edge of time track
// write complement - read strobe
tp1(ut);
// NB we don't also write the complement
tp2(ut);
tp3(ut);
tp4(ut);
}
if(doreq) calc_ut_req(pdp, ut);
}
static void
handle_ut(PDP6 *pdp, IOdev *dev, int cmd)
{
Ut551 *ut = (Ut551*)dev->dev;
switch(cmd) {
case IOB_RESET:
case IOB_CONO_CLR:
ut->incomp_block = 0;
ut->wren = 0;
ut->time_flag = 0;
ut->info_error = 0;
ut->illegal_op = 0;
ut->tape_end_flag = 0;
ut->jb_done_flag = 0;
ut->units_select = 0;
ut->tape_end_en = 0;
ut->jb_done_en = 0;
ut->go = 0;
ut->rev = 0;
ut->time_en = 0;
ut->time = 0;
ut->fcn = 0;
ut->units = 0;
ut->pia = 0;
ut->state = RW_NULL;
break;
case IOB_CONO_SET:
//printf("CONO UT %o (PC %06o)\n", (int)IOB&0777777, pdp->pc);
if(IOB & F1) ut->units_select = 1;
if(IOB & F2) ut->tape_end_en = 1;
if(IOB & F3) ut->jb_done_en = 1;
if(IOB & F4) ut->go = 1;
if(IOB & F5) ut->rev = 1;
if(IOB & F6) ut->time_en = 1;
ut->time |= (IOB>>27) & 3;
ut->fcn |= (IOB>>24) & 7;
ut->units |= (IOB>>21) & 7;
ut->pia |= (IOB>>18) & 7;
// command is effective before selection changes
if(ut->sel) uxsetmotion(ut->sel, ut->go, ut->rev);
utsel(ut);
if(ut->time == 0) {
// bit strange for DN and WRTM
ut->state = RW_RQ;
} else {
static int dlytab[4] = { 0, 35000000, 225000000, 300000000 };
ut->dlyend = simtime + dlytab[ut->time];
ut->start_dly = 1;
// T CLEAR
ut->tbm = 0;
ut->tdata = 0;
ut->tmk = 0;
ut->uteck = 0;
}
break;
case IOB_STATUS:
if(ut->units_select) IOB |= F19;
if(ut->tape_end_en) IOB |= F20;
if(ut->jb_done_en) IOB |= F21;
if(ut->go) IOB |= F22;
if(ut->rev) IOB |= F23;
if(ut->time_en) IOB |= F24;
IOB |= ut->time << 9;
IOB |= ut->fcn << 6;
IOB |= ut->units << 3;
IOB |= ut->pia;
break;
}
calc_ut_req(pdp, ut);
}
static void
handle_uts(PDP6 *pdp, IOdev *dev, int cmd)
{
Ut551 *ut = (Ut551*)dev->dev;
switch(cmd) {
case IOB_STATUS:
if(ut->start_dly) IOB |= F25;
if(ut->state == RW_RQ) IOB |= F26;
if(ut->state == RW_ACTIVE) IOB |= F27;
if(ut->state == RW_NULL) IOB |= F28;
if(ut->incomp_block) IOB |= F29;
if(ut->wren) IOB |= F30;
if(ut->time_flag) IOB |= F31;
if(ut->info_error) IOB |= F32;
if(ut->illegal_op) IOB |= F33;
if(ut->tape_end_flag) IOB |= F34;
if(ut->jb_done_flag) IOB |= F35;
break;
}
}
static Ut551 ut;
static IOdev ut_dev = { 0, 0210, &ut, handle_ut, cycle_ut };
static IOdev uts_dev = { 0, 0214, &ut, handle_uts, nil };
static void
calc_ut_req(PDP6 *pdp, Ut551 *ut)
{
int req = 0;
if(ut->pia &&
(ut->time_flag && ut->time_en ||
ut->jb_done_flag && ut->jb_done_en ||
ut->tape_end_flag && ut->tape_end_en ||
ut->illegal_op || ut->info_error))
req = 0200>>ut->pia;
setreq(pdp, &ut_dev, req);
}
Ut551*
attach_ut(PDP6 *pdp, Dc136 *dc)
{
ut.dc = dc;
ut.dcdev = 1;
installdev(pdp, &ut_dev);
installdev(pdp, &uts_dev);
return &ut;
}