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:
11
newemu/Makefile
Normal file
11
newemu/Makefile
Normal 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
27
newemu/args.h
Normal 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
66
newemu/audio.c
Normal 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
781
newemu/chargen.inc
Normal 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
240
newemu/common.c
Normal 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
34
newemu/common.h
Normal 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
182
newemu/dc.c
Normal 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
632
newemu/dis340.c
Normal 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
172
newemu/ge.c
Normal 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, >yi_dev, ireq);
|
||||
|
||||
int oreq = 0;
|
||||
if(ge->out_pia && ge->out_ready)
|
||||
oreq = 0200>>ge->out_pia;
|
||||
setreq(pdp, >yo_dev, oreq);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
attach_ge(PDP6 *pdp)
|
||||
{
|
||||
installdev(pdp, >yi_dev);
|
||||
installdev(pdp, >yo_dev);
|
||||
}
|
||||
5486
newemu/instgen.inc
Normal file
5486
newemu/instgen.inc
Normal file
File diff suppressed because it is too large
Load Diff
293
newemu/main.c
Normal file
293
newemu/main.c
Normal 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
102
newemu/panel10.c
Normal 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
91
newemu/panel6.c
Normal 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
2776
newemu/pdp6.c
Normal file
File diff suppressed because it is too large
Load Diff
323
newemu/pdp6.h
Normal file
323
newemu/pdp6.h
Normal 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
266
newemu/pt.c
Normal 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
134
newemu/tty.c
Normal 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
616
newemu/ut.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user