PDP7-Unix/sys/s4.s

"** 01-s1.pdf page 21
" s4

	" allocate a free disk block for a file (data or indirect)
alloc: 0
   -1			" Decrement the # free block numbers in the cache
   tad s.nfblks		" kept at s.fblks. Jump to 1f if no free blocks left.
   spa
   jmp 1f
   dac s.nfblks		" Update the count of free block numbers
   tad fblksp
   jms laci
   dac 9f+t
   jms copyz; dskbuf; 64
   lac 9f+t
   jms dskwr
   dzm .savblk
   lac 9f+t
   jmp alloc i		" Return from routine
1:
   lac s.nxfblk
   sna
   jms halt " OUT OF DISK
   dac s.fblks
   jms dskrd
   lac dskbuf
   dac s.nxfblk
   jms copy; dskbuf+1; s.fblks+1; 9
   lac d10
   dac s.nfblks
   jmp alloc+1

	" free the disk block whose number is in AC
free: 0
   lmq
   lac s.nfblks
   sad d10
   jmp 1f
   tad fblksp
   dac 9f+t
   lacq
   dac 9f+t i
   dzm .savblk
   isz s.nfblks
   jmp free i
1:
   lac s.nxfblk
   dac dskbuf
   jms copy; s.fblks+1; dskbuf+1; 9
   lacq
   dac s.nxfblk
   jms dskwr
   dzm .savblk
   lac d1
   dac s.nfblks
   jmp free i				" Return from the routine
t = t+1

	" load AC indirect (without using indirect!)
	" AC/ address
	"   jms laci
	" AC/ contents of address
laci: 0
   and o17777				" clear everything but addr
   tad o200000				" make into "lac addr"
   dac .+1
   lac ..				" fetch
   jmp laci i				" return

"** 01-s1.pdf page 22

	" skip if AC between two values (inclusive)
	"   jms betwen; low_ptr; high_ptr
	"    <not between>
	"  <between>
	" listing has an alternate written in
	"  (which would require 'lac ptr' instead of 'ptr' args?)
betwen: 0
   lmq cmq			" get ~AC in MQ
   lac betwen i			" get low_ptr
   dac 9f+t
   isz betwen			" skip low_ptr
   lacq				" get ~AC (-AC-1) from MQ
   tad 9f+t i			" get low-AC-1
   sma				" negative (AC >= low)?
   jmp 1f			"  no, return w/o skip
   lac betwen i			" fetch high_ptr
   dac 9f+t
   isz betwen			" skip high_ptr
   lacq				" get -AC-1
   tad 9f+t i			" add to high value (high-AC-1)
   cma				" complement (AC-high)
   spa sna			" AC-high <= 0?
1:
   isz betwen			"  no: give happy (skip) return
   lacq				" restore ~AC
   cma				" restore AC
   jmp betwen i			" return w/o skip

	" copy memory
	" call:
	"   jms copy; src; dest; count
copy: 0
   -1
   tad copy i
   dac 8
   isz copy
   -1
   tad copy i
   dac 9
   isz copy
   -1
   tad copy i
   cma
   dac 9f+t
   isz copy
1:
   lac 8 i
   dac 9 i
   isz 9f+t
   jmp 1b
   jmp copy i

	" copy zeroes (clear memory)
	" call:
	"   jms copyz; pointer; count
copyz: 0
   -1
   tad copyz i			" get call PC
   dac 8			" save in index (pre-increments)
   isz copyz			" skip pointer
   -1
   tad copyz i			" get count-1
   cma				" get negative count
   dac 9f+t			" save in t0
   isz copyz			" skip count
1:
   dzm 8 i			" zero word
   isz 9f+t			" done?
   jmp 1b			"  no: loop
   jmp copyz i			" return
t = t+1

	" put queued character
	" CALLED FROM PI: AVOIDS INDIRECT!!
	" queue number in AC
putchar: 0
"** 01-s1.pdf page 23
   dac 9f+t
   cla
   jms takeq
      jmp putchar i
   tad o40001
   dac .+4
   lac 9f+t
   jms putq
   lac char
   dac q2+1 ..
   isz putchar
   jmp putchar i
t = t+1

	" get queued character
	" CALLED FROM PI: AVOIDS INDIRECT!!
	" queue number in AC:
	"  1: tty input
	"  2: tty output
	"  3: display keyboard
	"  4: paper tape reader
	"  5: paper tape punch
getchar: 0
   jms takeq
      jmp i getchar
   tad o200001
   dac .+3
   cla
   jms putq
   lac q2+1 ..
   isz getchar
   jmp i getchar

	" CALLED FROM PI: AVOIDS INDIRECT!!
takeq: 0
   rcl
   tad lacq1
   dac .+7
   tad o640000
   dac .+17
   tad d1
   dac .+14
   tad o500000
   dac .+5
   lac q1 ..
   sna
   jmp takeq i
   dac lnkaddr
   sad q1+1 ..
   jmp .+5
   tad o200000
   dac .+1
   lac q2 ..
   jmp .+3
   cla
   dac q1+1 ..
   dac q1 ..
   isz takeq
   lac lnkaddr
   jmp i takeq

putq: 0
   rcl
   tad dacq1
   dac .+14
   tad d1
   dac .+13
   tad o140000
   dac .+1
   lac q1-1 ..
"** 01-s1.pdf page 24
   sna
   jmp .+6
   tad o40000
   dac .+2
   lac lnkaddr
   dac q2 ..
   jmp .+3
   lac lnkaddr
   dac q1 ..
   dac q1+1 ..
   jmp putq i

	" NOTE!! srcdbs, collaps, dskrd, dskwr share the same "temp" vars:
	" "t0" temp!!
	" "t1" contains pointer to (addr, buffer)
	" "t2" contains block number
	
	" check if disk block number in AC in memory
	" give skip return if block NOT found

srcdbs: 0
   dac 9f+t+2   "* lmq			" save block number in t2
   -ndskbs				" loop for number of buffers
   dac 9f+t				" in t0
   law dskbs	"* -1 dac 8 written	" get address of first buffer
   dac 9f+t+1	"* lacq			" in t1
1:
   lac 9f+t+2	"** crossed out		" get desired block number
   sad 9f+t+1 i	"** "8 i" written	" match buffer block?
   jmp srcdbs i				"  yes: return without skip
   law 65	"** crossed out		" no: advance to next buffer
   tad 9f+t+1	"** crossed out isz 8 written
   dac 9f+t+1
   isz 9f+t
   jmp 1b
   isz srcdbs				" block not found: give skip return
   jmp srcdbs i

collapse: 0
   cla					" look for free buffer
   jms srcdbs				" found?
      jmp 1f				"  yes
   law dskbs				" no: reuse last buffer
   dac 9f+t+1	"** 9f+t+1 crossed out: 8 written in
1:
		"** written: tad dm1
		"** written: dac 8
   lac 9f+t+1	"** 9f+t+1 crossed out: 8 written in
   dac 0f+1				" save as copy dest
   tad d65	"** crossed out w/ d2	" get start of next buffer
   dac 0f				" save as copy src
   cma
   tad d1
   tad edskbsp				" subtract from end of buffers
   and o17777				" mask to 13 bits
   sna					" non-zero count?
   jmp 0f+3				"  no: skip copy
   dac 0f+2				" save as copy length
   jms copy; 0:..; ..; ..		" slide buffers up
   -65
   tad edskbsp				" get addr of last buffer
   dac 9f+t				" save in t0
   tad d1				" get block data pointer
   dac 0f				" save as copy dest
   lac dskaddr				" get block number
   dac 9f+t i				" save in buffer header
   jms copy; dskbuf; 0:..; 64		" copy dskbuf to last buffer
   jmp collapse i

	" read logical disk block number (2..7999) in AC into dskbuf
dskrd: 0
   jms betwen; d2; d7999

"** 01-s1.pdf page 25
      jms halt			" bad block number
   sad dskaddr			" block currently in dskbuf
   jmp dskrd i			"  yes: return
   dac dskaddr			" save block address
   jms srcdbs			" in memory?
      jmp 1f			"  yes
   lac dskaddr			" no: read from disk
   jms dskio; 06000
   jmp 2f
1:
   dzm 9f+t+1 i
   law 1
   tad 9f+t+1
   dac .+2
   jms copy; ..; dskbuf; 64
2:
   jms collapse
   jmp dskrd i

	" write a file block (data, inode or indirect)
	" AC/ block
dskwr: 0
   jms betwen; d2; d7999
      jms halt
   jms dskio; 07000
   lac dskaddr
   jms srcdbs
      dzm 9f+t+1 i
   jms collapse
   jmp dskwr i
t = t+3

	" called to read/write logical block into "dskbuf"
	" AC/ block
	"   jms dskio; DSLD_BITS
dskio: 0
   dac dskaddr
   cll; idiv; 80
   dac 9f+t
   lacq
   idiv; 10
   dac 9f+t+1
   lls 22
   xor 9f+t+1
   als 8
   dac 9f+t+1
   lac 9f+t
   idiv; 10
   dac 9f+t
   lls 22
   xor 9f+t
   xor 9f+t+1
   xor o200000
   dac 9f+t
   jms dsktrans; -64; dskbuf; 9f+t; dskio
   isz dskio
   jmp dskio i
t = t+1

	" perform disk I/O (both filesystem buffer and swapping)
	" passed physical (BCD) disk address
	" called:
	"   jms dsktrans; -WC; MAC; addr_ptr; dsld_ptr
dsktrans: 0
   -10
   dac 9f+t
1:
   -1
   tad dsktrans
   dac 12
"** 01-s1.pdf page 26
   dscs				" clear status register
   lac 12 i
   dslw				" load WC
   lac 12 i
   dslm				" load MAC
   lac 12 i
   jms laci
   dsld				" load TA & SA
   dzm .dskb
   lac 12 i
   jms laci
   jms laci
   dsls				" load status
   lac .dskb			" check for interrupt
   sna
   jmp .-2
   lac .dske			" get status from interrupt
   sma
   jmp 12 i			" return
   isz 9f+t
   jmp 1b
   jms halt " 10 disk errors
t = t+1

halt: 0
   isz 9f+t			" spin for a while (process interrupts)
   jmp .-1
   iof				" disable interrupts
   hlt				" halt
   jms copy; law; 4096; 4096	" continued: copy system up to user memory?
   hlt; jmp .-1			" halt for good
t = t+1