get "streams.d"

external
	[ 
	readmc12
	Gets
	Puts
	Endofs
	SetBlock
	dsp
	OpenFile
	Closes
	Wss
	Zero
	Wos
	CallSwat
	]


static
	[ 
	memnos
	stream
	MEMORY
	]

manifest
[
	nmems = 2
]

//	A BCPL STRING
structure BS : [ LENGTH byte
		CHAR↑1,255 byte
		]


structure [ lh byte; rh byte ] 


let readmc12(file,mcvec,adcomp) be //file is the string name of the .mb file,
//mcvec is a 256*4 word vector into which the bits will be crammed,
//and adcomp is the quantity xor'ed with the address before cramming

[


	MEMORY = mcvec
	Zero(MEMORY,256*4)
	let x = ReadMC1MB(file,adcomp) //read mc1
	if x ne 0 then [ Wss(dsp,"*n*n");Wss(dsp,x); finish ]
]



		


and ReadMC1MB(file,adcomp) = valof
// file is a filename
// returns 0 if OK, otherwise error string
[	stream = OpenFile(file)
	if stream eq 0 then resultis "Can't open .MB file"
	let curmemx, curaddr = -1, 0
	let memnames = vec nmems
	   memnames!0 = "IM"
	   memnames!1 = "IMX"
	let memwidths = table[ #110;#100 ] 
	let mnos = vec nmems
	memnos = mnos
	SetBlock(memnos, -1, nmems)


  [	if Endofs(stream) then resultis "Unexpected end of stream"
	let blocktype = Gets(stream)
	switchon blocktype into
	 [
		case 0:	// end of data
			Closes(stream);resultis 0

	   case 2:	// set address
	    [ curmemx = findmem(Gets(stream))
			if curmemx eq -1 then resultis "Bad Memory Number"
	      curaddr = Gets(stream)
	      endcase
	    ]

	   case 1:	// data word
	    [ Gets(stream) //discard sequence number
	      switchon curmemx into
	       [
				case 0:	//IM- discard value
						[
						Gets(stream);	//5 words
						Gets(stream);
						Gets(stream)
						Gets(stream);
						Gets(stream);
						endcase
						]
				case 1:	//IMX- put value into vector
						[
						let wd0=Gets(stream);	//4 words
						let wd1=Gets(stream);
						let wd2=Gets(stream)
						let wd3 = Gets(stream);
						let r =WriteMCData(curaddr,wd0,wd1,wd2,wd3,adcomp)
						if r ne 0 then resultis r
						endcase
						]
				 default: resultis "Data for undefined memory"
	       ]
	      curaddr = curaddr+1
	      endcase
	    ]

	   case 4:	// define memory
		[
			let memno = Gets(stream)
			let width = Gets(stream)
			let name = vec 128
			readname(name)
			for j = 0 to nmems-1 do
			if strequal(name, memnames!j) then
			[
				if width ne memwidths!j then
				resultis "Bad width"
				memnos!j = memno
				endcase
			]
			resultis "Bad memory name"
		]

	   case 5:	// define symbol
	    [
			let memno = Gets(stream)
	      let val = Gets(stream)
	      let name = vec 128
	      readname(name)
	      let memx = findmem(memno)
	      if memx eq -1 then resultis "Bad memory #"
	      endcase
	    ]
	   default: resultis "Invalid block type"
	 ]
  ] repeat
]

and noop(x, y, z) be [ ]

and findmem(memno) = valof
[
	for j = 0 to nmems-1 do
	if memnos!j eq memno then resultis j
	resultis -1
]

and readname(strg) be
[	let j = 0
	[
	let wd = Gets(stream)
	if wd<<lh eq 0 break
	j = j+1
	strg>>BS.CHAR↑j = wd<<lh
	if wd<<rh eq 0 break
	j = j+1
	strg>>BS.CHAR↑j = wd<<rh
	] repeat
	strg>>BS.LENGTH = j
]

and strequal(str1, str2) = valof
[
	for i = 0 to str1>>BS.LENGTH do
	if str1>>BS.CHAR↑i ne str2>>BS.CHAR↑i resultis false
	resultis true
]

and WriteMCData(addr,wd0,wd1,wd2,wd3,adcomp) =valof
[
		let memp = MEMORY+ (4*(addr xor adcomp)) //note that some of the address bits are complemented. 
		memp!0 = wd0
		memp!1 = wd1
		memp!2 = wd2
		memp!3 = (wd3 % 1) //set the low bit of the last word to mean "defined"
		resultis 0

]