add games/blit

front
aiju 2017-03-28 19:43:09 +00:00
parent f14e277c58
commit 447672be5c
16 changed files with 22734 additions and 0 deletions

219
sys/src/games/blit/blit.c Normal file
View File

@ -0,0 +1,219 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <keyboard.h>
#include <mouse.h>
#include <cursor.h>
#include "dat.h"
#include "fns.h"
int baud = 40000;
int scale = 1;
Rectangle picr;
Image *tmp, *bg;
Channel *keych, *uartrxch, *uarttxch;
Mousectl *mc;
int daddr;
u16int dstat;
u8int invert;
int vblctr, uartrxctr;
Rectangle updated;
u32int colbgv, colfgv;
Image *colbg, *colfg;
int realcolors;
static void
screeninit(void)
{
Point p;
p = divpt(addpt(screen->r.min, screen->r.max), 2);
picr = (Rectangle){subpt(p, Pt(scale * SX/2, scale * SY/2)), addpt(p, Pt(scale * SX/2, scale * SY/2))};
if(tmp != nil) freeimage(tmp);
tmp = allocimage(display, Rect(0, 0, scale * SX, scale > 1 ? 1 : scale * SY), CHAN1(CMap, 1), scale > 1, 0);
if(bg != nil) freeimage(bg);
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
colbg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, colbgv);
colfg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, colfgv);
draw(screen, screen->r, bg, nil, ZP);
updated = Rect(0, 0, SX, SY);
}
static void
redraw(void)
{
static uchar pic[SX*SY/8];
ushort *p;
uchar *q;
int o, n;
Mouse m;
Rectangle r;
if(nbrecvul(mc->resizec) > 0){
if(getwindow(display, Refnone) < 0)
sysfatal("resize failed: %r");
screeninit();
}
while(nbrecv(mc->c, &m) > 0){
if(ptinrect(m.xy, picr)){
mousex = picr.max.x - m.xy.x - 1;
mousey = picr.max.y - m.xy.y - 1;
}
n = m.buttons >> 2 & 1 | m.buttons & 2 | m.buttons << 2 & 4;
if(n != mousebut){
mousebut = n;
irq |= INTMOUSE;
}
}
if(Dy(updated) <= 0 || Dx(updated) <= 0)
return;
assert(daddr + sizeof(pic) <= sizeof(ram));
r = tmp->r;
if(updated.min.y > r.min.y)
r.min.y = updated.min.y;
if(updated.max.y < r.max.y)
r.max.y = updated.max.y;
o = r.min.y*(SX/8);
p = ram + (daddr + o) / 2;
q = pic + o;
for(n = Dy(r)*(SX/16); --n >= 0; ){
*q++ = invert ^ *p >> 8;
*q++ = invert ^ *p++;
}
loadimage(tmp, r, pic+o, Dy(r)*(SX/8));
if(realcolors){
draw(screen, rectaddpt(r, picr.min), colfg, nil, r.min);
draw(screen, rectaddpt(r, picr.min), colbg, tmp, r.min);
}else
draw(screen, rectaddpt(r, picr.min), tmp, nil, r.min);
updated = Rect(SX, SY, 0, 0);
flushimage(display, 1);
}
static uchar
keymap[] = {
[Kup-KF] 0xf1,
[Kdown-KF] 0xf2,
[Kleft-KF] 0xf3,
[Kright-KF] 0xf4,
[1] 0xf6, /* PF1 */
[2] 0xf7, /* PF2 */
[3] 0xf8, /* PF3 */
[4] 0xf9, /* PF4 */
[12] 0xfe, /* SET-UP */
[Kpgdown-KF] 0xb0, /* SCROLL */
[Kins-KF] 0xe0, /* BREAK */
};
static void
keyproc(void *)
{
int fd, cfd, ch, rc;
static char buf[256];
char *p;
Rune r;
fd = open("/dev/cons", OREAD);
if(fd < 0)
sysfatal("open: %r");
cfd = open("/dev/consctl", OWRITE);
if(cfd < 0)
sysfatal("open: %r");
fprint(cfd, "rawon");
for(;;){
rc = read(fd, buf, sizeof(buf) - 1);
if(rc <= 0)
sysfatal("read /dev/cons: %r");
for(p = buf; p < buf + rc && (p += chartorune(&r, p)); ){
if(r == Kend){
close(fd);
threadexitsall(nil);
}
ch = r;
if(ch == '\n') ch = '\r';
else if(ch >= KF){
if(ch >= KF + nelem(keymap)) continue;
ch = keymap[ch - KF];
if(ch == 0) continue;
}else if(ch >= 0x80) continue;
send(keych, &ch);
}
}
}
void
usage(void)
{
fprint(2, "usage: %s [-b baud] [-C bg,fg] [-d] [-t [net!]host[!service]]\n", argv0);
threadexitsall("usage");
}
void
threadmain(int argc, char **argv)
{
int n;
static Cursor blank;
char *telnet;
char *p;
extern int diag;
telnet = nil;
ARGBEGIN{
case 'b':
baud = strtol(EARGF(usage()), &p, 0);
if(*p != 0) usage();
break;
case 't':
telnet = EARGF(usage());
break;
case 'C':
if(realcolors) usage();
realcolors++;
p = EARGF(usage());
colbgv = strtol(p, &p, 16) << 8 | 0xff;
if(*p++ != ',') usage();
colfgv = strtol(p, &p, 16) << 8 | 0xff;
if(*p != 0) usage();
break;
case 'd':
diag++;
break;
default: usage();
}ARGEND;
if(argc != 0) usage();
keych = chancreate(sizeof(int), 64);
uartrxch = chancreate(sizeof(int), 128);
uarttxch = chancreate(sizeof(int), 128);
if(telnet != nil) telnetinit(telnet);
meminit();
if(initdraw(nil, nil, nil) < 0)
sysfatal("initdraw: %r");
screeninit();
proccreate(keyproc, nil, mainstacksize);
mc = initmouse(nil, screen);
if(mc == nil)
sysfatal("initmouse: %r");
setcursor(mc, &blank);
cpureset();
for(;;){
keycheck();
n = step();
vblctr += n;
if(vblctr >= VBLDIV){
irq |= INTVBL;
redraw();
vblctr -= VBLDIV;
}
if(uartrxctr > 0)
uartrxctr -= n;
}
}

1184
sys/src/games/blit/cpu.c Normal file

File diff suppressed because it is too large Load Diff

31
sys/src/games/blit/dat.h Normal file
View File

@ -0,0 +1,31 @@
typedef signed char s8int;
typedef signed short s16int;
typedef signed long s32int;
extern u32int curpc, irq;
extern int trace, debug;
extern ushort ram[128*1024];
extern int daddr;
extern ushort dstat;
extern uchar invert;
extern int mousex, mousey, mousebut;
extern int vblctr, uartrxctr;
extern int baud;
enum {
INTKEY = 1,
INTMOUSE = 2,
INTUART = 4,
INTVBL = 8,
};
enum {
SX = 800,
SY = 1024,
FREQ = 8000*1000,
VBLDIV = FREQ / 60,
};

BIN
sys/src/games/blit/diagbits Normal file

Binary file not shown.

8
sys/src/games/blit/fns.h Normal file
View File

@ -0,0 +1,8 @@
u16int memread(u32int);
void memwrite(u32int, u16int, u16int);
int intack(int);
int step(void);
void meminit(void);
void cpureset(void);
void keycheck(void);
void telnetinit(char *);

180
sys/src/games/blit/mem.c Normal file
View File

@ -0,0 +1,180 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <bio.h>
#include <mouse.h>
#include "dat.h"
#include "fns.h"
u32int irq;
u32int irql[8] = {
[1] INTVBL,
[2] INTKEY,
[4] INTMOUSE,
[5] INTUART,
};
int diag;
ushort ram[128*1024];
ushort rom[3*4096];
Channel *keych;
Channel *uartrxch, *uarttxch;
int mousex, mousey, mousebut;
int yes;
u8int kbdctrl, uartctrl;
enum {
ACIATXMASK = 0x60,
ACIATXIRQ = 0x20,
ACIARXIRQ = 0x80,
};
int keybuf = -1;
int uartrxbuf = -1;
int uarttxbuf = -1;
void
meminit(void)
{
int i, x;
Biobuf *bp;
char *s;
ushort *p, *q;
p = rom;
if(diag){
bp = Bopen("diagbits", OREAD);
if(bp == nil) sysfatal("Bopen: %r");
Bread(bp, rom, sizeof(rom));
Bterm(bp);
return;
}
for(i = 0; i < 6; i++){
bp = Bopen(smprint("rom%d", i), OREAD);
if(bp == nil) sysfatal("Bopen: %r");
q = p;
for(;;){
s = Brdline(bp, '\n');
if(s == nil || Blinelen(bp) == 0) break;
s[Blinelen(bp) - 1] = 0;
x = strtol(s, nil, 8);
if((i & 1) != 0)
*p |= x << 8;
else
*p |= x;
p++;
}
if((i & 1) == 0) p = q;
Bterm(bp);
}
write(3, rom, sizeof(rom));
}
void
keycheck(void)
{
yield();
if(keybuf < 0)
nbrecv(keych, &keybuf);
if(keybuf >= 0 && (kbdctrl & ACIARXIRQ) != 0)
irq |= INTKEY;
else
irq &= ~INTKEY;
if(uartrxbuf < 0 && uartrxctr <= 0){
nbrecv(uartrxch, &uartrxbuf);
uartrxctr = FREQ * 11 / baud;
}
if(uarttxbuf >= 0 && nbsend(uarttxch, &uarttxbuf) > 0)
uarttxbuf = -1;
if(uartrxbuf >= 0 && (uartctrl & ACIARXIRQ) != 0 || uarttxbuf < 0 && (uartctrl & ACIATXMASK) == ACIATXIRQ)
irq |= INTUART;
else
irq &= ~INTUART;
}
u16int
memread(u32int a)
{
int rc;
a &= 0x3fffff;
if(a < 8) a += 0x40000;
if(a < 0x40000) return ram[a/2];
if(a >= 0x40000 && a < 0x40000 + sizeof(rom))
return rom[(a - 0x40000)/2];
switch(a & ~1){
case 01400000: return mousey;
case 01400002: return mousex;
case 01400010: /* uart status */
rc = 0;
if(uartrxbuf >= 0) rc |= 1;
if(uarttxbuf < 0) rc |= 2;
return rc | rc << 8;
case 01400012: /* uart data */
rc = uartrxbuf;
uartrxbuf = -1;
yes=1;
return rc | rc << 8;
case 01400020:
case 01400024:
irq &= ~INTMOUSE;
return mousebut | mousebut << 8;
case 01400026: return 0; /* mouse: unknown purpose */
case 01400030: return daddr >> 2; /* display address */
case 01400040: return dstat; /* display status */
case 01400060: /* keyboard status */
rc = 2;
if(keybuf >= 0) rc |= 1;
return rc | rc << 8;
case 01400062: /* keyboard data */
rc = keybuf;
keybuf = -1;
return rc | rc << 8;
}
print("read %.8o (curpc = %.6x)\n", a, curpc & 0x3fffff);
return 0;
}
void
memwrite(u32int a, u16int v, u16int m)
{
extern Rectangle updated;
int x, y;
a &= 0x3fffff;
if(a < 0x40000){
if(a >= daddr){
y = (a - daddr) / 100;
x = (((a & ~1) - daddr) % 100) * 8;
if(updated.min.x > x) updated.min.x = x;
if(updated.max.x < x+16) updated.max.x = x+16;
if(updated.min.y > y) updated.min.y = y;
if(updated.max.y <= y) updated.max.y = y+1;
}
ram[a/2] = ram[a/2] & ~m | v & m;
return;
}
switch(a & ~1){
case 01400010: uartctrl = v; return;
case 01400012: uarttxbuf = (uchar) v; return;
case 01400024: return; /* mouse: purpose unknown */
case 01400026: return; /* mouse: purpose unknown */
case 01400030: daddr = ((daddr >> 2) & ~m | v & m) << 2; return;
case 01400040: dstat = dstat & ~m | v & m; invert = -(dstat & 1); updated = Rect(0, 0, SX, SY); return;
case 01400056: /* sound; exact function unknown */ return;
case 01400060: kbdctrl = v; return;
case 01400062: /* reset keyboard */ return;
case 01400070: irq &= ~INTVBL; return;
case 01400156: /* sound; exact function unknown */ return;
}
print("write %.8o = %.4x (mask = %.4x, curpc = %.6x)\n", a, v, m, curpc & 0x3fffff);
}
int
intack(int l)
{
return 24+l;
}

12
sys/src/games/blit/mkfile Normal file
View File

@ -0,0 +1,12 @@
</$objtype/mkfile
BIN=/$objtype/bin
TARG=blit
HFILES=dat.h fns.h
OFILES=\
blit.$O\
cpu.$O\
mem.$O\
telnet.$O\
</sys/src/cmd/mkone

88
sys/src/games/blit/mmap Normal file
View File

@ -0,0 +1,88 @@
- main CPU is a MC68000 running at 8 MHz.
the exact clock speed is most likely one of: 7.9872, 7.68 or 7.3728 MHz (to divide to 19200 baud)
- display is 800x1024, refreshed at 30 Hz (60 Hz interlaced).
it simply displays the 100K framebuffer from the address given in register 030.
- the host is connected through a UART running at 19200 baud.
- the keyboard is connected through a UART running at an unknown baudrate.
- the mouse is connected through some unknown circuitry.
memory map
start end purpose
0x00000 0x00008 see register 050 below
0x00008 0x40000 RAM (256K)
0x40000 ??? ROM (24K ?) (not known if mirrored)
0x60000 ??? memory mapped I/O
mmio addresses (in *octal*):
0000 16-bit mouse y
0002 16-bit mouse x
0011 8-bit terminal UART status/control (MC 6850 ACIA)
0013 8-bit terminal UART data
the software uses 2 stop bits, no parity, 8 bits; clock divided by 16
0021 8-bit mouse buttons
bit 0: rmb
bit 1: mmb
bit 2: lmb
reading clears the mouse interrupt
0025 8-bit second copy of 0021 (?)
0027 8-bit ???
only the ROM binaries contain references to 0025, 0027 in buttons.c.
the corresponding source code appears to have been deleted.
possibly some older variant of the button hardware?
0030 16-bit start address of framebuffer divided by 4 (800*1024/8 = 100K bytes)
0040 16-bit status/control register of display
bit 0: invert display
with this bit set 0 bits are white and 1 bits are black (most software does this).
0050 16-bit writing different values makes 0-8 either mapped to 0x40000 or error out (details unclear)
resets so that they map to the reset vector at 0x40000.
0056 8-bit some kind of sound-making device (standard programmable timer + piezoelectric speaker?)
0156 referenced by demo pacman.
0256
0060 8-bit keyboard status/control register (MC 6850 ACIA)
the software uses 2 stop bits, no parity, 8 bits; clock divided by 16
0062 8-bit keyboard data register
0070 16-bit? acknowledge vblank interrupt; software writes 0
tx to the keyboard sets the 7 lights and can also ring the bell.
could deduce the order of lights from diag.c.
writing 2 is used to sound the bell.
irq lines; using the 68k autovectoring
vector 1 (0x64) is vblank
vector 2 (0x68) is keyboard
vector 4 (0x70) is mouse buttons
vector 5 (0x74) is uart
MC 6850 bits:
+0 (r) status register
bit 0: receive buffer full
bit 1: transmit buffer empty
bit 2: data carrier detected (inverted)
bit 3: clear-to-send (inverted)
bit 4: framing error
bit 5: receiver overrun
bit 6: parity error
bit 7: irq active
+0 (w) control register
bit 1-0: clock divider
00: /1
01: /16
10: /64
11: master reset
bit 4-2: parity and stop bits (see datasheet)
bit 6-5:
RTS/ is high only if these bits are 10
TX interrupts are enabled only if these bits are 01
break is transmitted continuously if these bits are 11
bit 7: RX interrupt enabled

4096
sys/src/games/blit/rom0 Normal file

File diff suppressed because it is too large Load Diff

4096
sys/src/games/blit/rom1 Normal file

File diff suppressed because it is too large Load Diff

4096
sys/src/games/blit/rom2 Normal file

File diff suppressed because it is too large Load Diff

4096
sys/src/games/blit/rom3 Normal file

File diff suppressed because it is too large Load Diff

2239
sys/src/games/blit/rom4 Normal file

File diff suppressed because it is too large Load Diff

2239
sys/src/games/blit/rom5 Normal file

File diff suppressed because it is too large Load Diff

149
sys/src/games/blit/telnet.c Normal file
View File

@ -0,0 +1,149 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
#include "dat.h"
#include "fns.h"
Channel *telnetrxch, *telnettxch;
extern Channel *uartrxch, *uarttxch;
int teldebug;
enum {
SE = 240,
NOP = 241,
BRK = 243,
IP = 244,
AO = 245,
AYT = 246,
EC = 247,
EL = 248,
GA = 249,
SB = 250,
WILL = 251,
WONT = 252,
DO = 253,
DONT = 254,
IAC = 255,
XMITBIN = 0,
ECHO = 1,
SUPRGA = 3,
LINEEDIT = 34,
};
int telfd;
static void
netrproc(void *)
{
static uchar buf[512];
int n, c;
uchar *p;
for(;;){
n = read(telfd, buf, sizeof(buf));
if(n < 0) sysfatal("read: %r");
for(p = buf; p < buf + n; p++){
c = *p;
send(telnetrxch, &c);
}
}
}
static void
netwproc(void *)
{
static uchar buf[512];
int c;
uchar *p;
for(;;){
recv(telnettxch, &c);
p = buf;
do
*p++ = c;
while(nbrecv(telnettxch, &c) > 0);
if(write(telfd, buf, p - buf) < p - buf)
sysfatal("write: %r");
}
}
static void
telnetrthread(void *)
{
int c;
for(;;){
recv(telnetrxch, &c);
if(c != IAC){
send(uartrxch, &c);
continue;
}
recv(telnetrxch, &c);
switch(c){
case NOP: break;
case WILL:
recv(telnetrxch, &c);
if(teldebug) fprint(2, "WILL %d\n", c);
break;
case WONT:
recv(telnetrxch, &c);
if(teldebug) fprint(2, "WONT %d\n", c);
break;
case DO:
recv(telnetrxch, &c);
if(teldebug) fprint(2, "DO %d\n", c);
break;
case DONT:
recv(telnetrxch, &c);
if(teldebug) fprint(2, "DONT %d\n", c);
break;
case IAC:
send(uartrxch, &c);
break;
default:
fprint(2, "unknown telnet command %d\n", c);
}
}
}
static void
cmd(int a, int b)
{
send(telnettxch, &a);
if(b >= 0) send(telnettxch, &b);
}
static void
telnetwthread(void *)
{
int c;
for(;;){
recv(uarttxch, &c);
send(telnettxch, &c);
if(c == 0xff)
send(telnettxch, &c);
}
}
void
telnetinit(char *dialstr)
{
telfd = dial(netmkaddr(dialstr, nil, "telnet"), nil, nil, nil);
if(telfd < 0) sysfatal("dial: %r");
telnetrxch = chancreate(sizeof(int), 128);
telnettxch = chancreate(sizeof(int), 128);
cmd(WILL, XMITBIN);
cmd(DO, XMITBIN);
cmd(DONT, ECHO);
cmd(DO, SUPRGA);
cmd(WILL, SUPRGA);
cmd(WONT, LINEEDIT);
cmd(DONT, LINEEDIT);
proccreate(netrproc, nil, mainstacksize);
proccreate(netwproc, nil, mainstacksize);
threadcreate(telnetrthread, nil, mainstacksize);
threadcreate(telnetwthread, nil, mainstacksize);
}

View File

@ -3,6 +3,7 @@
TARG=4s\
5s\
ana\
blit\
catclock\
festoon\
geigerstats\