2

I am trying to understand the elementary basics of using a pdp-11 (learned the instruction set in college, want to revisit this), wanting to shoot some characters out the TTO/DL11 as a first program (unless that is too complicated a first program).

Running on simh. show dev has

TTO, address=17777564-17777567, vector=64

Reading docs the tx buffer is at offset 566. Seeing other code at stackoverflow and some other pages there is/might be an mmu in the upper address space that say 177566 (octal) may put you there as registers are 16 bit not 22 bits as the show dev implies.

mov $0x32,r1
movb r1, @$0177566
mov $0177566,r2
mov $0x30,r3
movb r3,(r2)
mov $0x31,r3
movb r3,(r2)
halt

and nothing comes out.

load test.bin
go

can use set console telnet=4444 and telnet to that, no change. No doubt it is something I dont get about addressing beyond 16 bits but not quite sure where to go to figure this out.

Basically I want to, unless it is a lot of code (thousands of lines of asm) to get some characters to come out of the console, I want to start there to begin to "see" something, then build on that. So if I am close but not quite or if this is not the best peripheral to start with, where to go, they all are in that upper address space.

I am using a gnu tools

pdp11-aout-as --version
GNU assembler (GNU Binutils) 2.26.20160125
Copyright (C) 2015 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or later.
This program has absolutely no warranty.
This assembler was configured for a target of `pdp11-aout'.

So the syntax is a little goofy/non-standard. The pdp11 has been supported in binutils for a few releases at least now, wanting to also take advantage of that. Binary file format for simh was not too hard to figure out, single stepping it is matching the instructions I am wanting and feeding gnu assembler.

Tried on both the apt-got v3.8-1 version of simh pdp11 as well as the github got 4.0 version, same results. using the pdp11 simulator/executable.

sim> show config
PDP-11 simulator configuration

CPU, 11/73, NOCIS, idle disabled, autoconfiguration enabled, 256KB
SYSTEM
RHA, address=17776700-17776753, vector=254
RHB, disabled
CLK, 60Hz, address=17777546-17777547, vector=100
PCLK, disabled
PTR, address=17777550-17777553, vector=70, not attached
PTP, address=17777554-17777557, vector=74, not attached
TTI, address=17777560-17777563, vector=60, 7b
TTO, address=17777564-17777567, vector=64, 7p
CR, address=17777160-17777167, vector=230, 285 cards per minute, translation 029, not attached, CR11, auto EOF, unknown format
LPT, address=17777514-17777517, vector=200, not attached
DLI, disabled
DLO, disabled
...

EDIT

#define TKS (*((volatile unsigned *)0177560))
#define TKB (*((volatile unsigned *)0177562))
#define TPS (*((volatile unsigned *)0177564))
#define TPB (*((volatile unsigned *)0177566))

void punch ( unsigned x )
{
    while((TPS&0x80)==0) continue;
    TPB=x;
}

void notmain ( void )
{
    //unsigned ra;
    //for(ra=0x30;ra<0x37;ra++) punch(ra);
    punch(0x30);
    while((TPS&0x80)==0) continue;
    return;
}

which makes

Disassembly of section .text:

00000000 <start.o>:
   0:   15c6 2000       mov $20000, sp
   4:   09f7 001a       jsr pc, 22 <_punch+0x18>
    ...

0000000a <_punch>:
   a:   1166            mov r5, -(sp)
   c:   1185            mov sp, r5
   e:   17c0 ff74       mov *$177564, r0
  12:   45c0 ff7f       bic $-201, r0
  16:   03fb            beq e <_punch+0x4>
  18:   1d5f 0004 ff76  mov 4(r5), *$177566
  1e:   1585            mov (sp)+, r5
  20:   0087            rts pc
  22:   1166            mov r5, -(sp)
  24:   1185            mov sp, r5
  26:   17c0 ff74       mov *$177564, r0
  2a:   45c0 ff7f       bic $-201, r0
  2e:   03fb            beq 26 <_punch+0x1c>
  30:   15df 0030 ff76  mov $60, *$177566
  36:   17c0 ff74       mov *$177564, r0
  3a:   45c0 ff7f       bic $-201, r0
  3e:   03fb            beq 36 <_punch+0x2c>
  40:   1585            mov (sp)+, r5
  42:   0087            rts pc

Two problems, one I was not waiting for busy. On init/reset that is okay it is not busy. I think the kicker was that I halted before it could spit the character out. When I had the loop it spit out most of the characters. If I send out one character and halt it doesnt come out, but if I put the wait for busy to go zero after (last thing in notmain()) then that character comes out.

if I change it to this

#define TKS (*((volatile unsigned *)0177560))
#define TKB (*((volatile unsigned *)0177562))
#define TPS (*((volatile unsigned *)0177564))
#define TPB (*((volatile unsigned *)0177566))

void punch ( unsigned x )
{
    TPB=x;
    while((TPS&0x80)==0) continue;
}

void notmain ( void )
{
    unsigned ra;
    for(ra=0x30;ra<0x37;ra++) punch(ra);
    return;
}

It works quite nicely...thanks for getting me kick started.

Note from a manual:

In addition to the word length constraint on basic memory addressing
space, the uppermost 4K words of address space is always reserved for
UNIBUS 1/0 device registers. In a basic PDP-11/40 memory configura·
tion (without Management) all address references to the uppermost 4K
words of 16-bit address space (170000-177777) are converted to full
18-bit reference5 with bits 17 and 16 always set to 1. Thus, a 16·bit
reference to the 1/0 device register at address 173224 is automatically
internally converted to a full 18-bit reference to the register at address
773224. Accordingly, the basic PDP-11/40 configuration can directly
address up to 28K words of true memory, and 4K words of UNIBUS 1/0
device registers.

So that answer was right there I didnt look in the right place.

EDIT2:

In assembly, to meet the goal of sending a character out the tty, using gnu assembler syntax (* instead of @ and $ instead of #)

movb $0x32,*$0177566
pwait:
   tstb *$0177564
   bpl pwait
halt
old_timer
  • 69,149
  • 8
  • 89
  • 168
  • That generated PDP-11 code is actually very inefficient. The ready bit is the high bit of the low byte on purpose, that makes it easy to test with `TSTB @#0177564` then `BLT .-6` to complete the loop. Just thought you might like to know. – MAP Jul 17 '16 at 05:46
  • its a C compiler. I wouldnt use the word very, it does burn a register and add a couple of words, I could turn off optimization and possibly make it much worse. Put an operating system in front of it and it gets much worse. If I make the pointer a char then the compiler produces movb *$177564, r0; bge ..., which burns a register but is the same size as a tstb/bpl. The punch status and punch buffer are defined as 16 bit registers with unused bits, so not incorrect to define them as such, would have to know that it is safe to access the 16 bit register as a byte. – old_timer Jul 17 '16 at 11:16
  • if we want to argue speed the compiler could have unrolled the loop, not used a register to feed the tty buffer, just shoved the bytes in movb $060,*$0177566, burns more instruction space overall but faster. It is a C compiler and it is actually doing a pretty good job as C compilers go. Same is true for any application of a high level language, you can always find tweaks to "improve" the output. – old_timer Jul 17 '16 at 11:21
  • But, the OQ was talking about learning to program in assembler. I was just pointing out a better way to do it. – MAP Jul 17 '16 at 11:35
  • understood, assembler was implied yes, bare-metal was the real goal. – old_timer Jul 17 '16 at 11:46
  • actually the goal was to spit a character out the tty in simh... – old_timer Jul 17 '16 at 11:47

1 Answers1

2

I think the problem is not using the DL11 correctly. You can't just give it a character any time you want to. You have to test the "ready" flag in the control register. Then, when it's ready send the character. Also, you can not reliably read back the value out of the data register. And then you are using that character as a memory pointer (there will certainly be memory down there, but writing into it probably wasn't what you intended).

You may also be interested in looking at the Retrocomputing Stack Exchange site. I'm probably not the only one hanging out there with PDP-11 experience, but I might be here.

Community
  • 1
  • 1
MAP
  • 812
  • 6
  • 10
  • Understood, some simulators you can bypass the init and go right for the tx buffer. The bigger question is am I even remotely on the right path, can I address within the 64K address space and hit these peripherals that claim to have a greater than 16 bit address, or is there some other hardware I have to tickle/setup first before doing these accesses to generate the extra address bits? – old_timer Jul 15 '16 at 11:22
  • Is there a simple way to determine if I am addressing the peripheral space or memory space with a 177xxx type of address? – old_timer Jul 15 '16 at 12:51
  • 1
    All normal references on the bare metal higher than (or equal) 176000 reference the I/O page. The only time it wouldn't is if you have memory management turned on. – MAP Jul 16 '16 at 02:15
  • Got it working! Thanks! Just needed a kick start or confidence I was roughly in the right direction. Can print characters out to the console now. – old_timer Jul 16 '16 at 04:06
  • What you should do is write up the results as an answer to the question for future seekers to find. – MAP Jul 16 '16 at 04:11