• Please review our updated Terms and Rules here

Receive input without echoing?

nockieboy

Experienced Member
Joined
May 12, 2017
Messages
261
Location
UK - Kent
Hi everyone,

As the title suggests, I'm trying to receive a lot of pasted code into a terminal running CP/M 2.2 and would like to receive the data and process it without it being automatically echoed back to the terminal as BDOS function 1 (C_READ) does.

I've tried using BDOS function 6 (C_RAWIO) to do this, but CP/M hangs with my implementation as I suspect it's never receiving a character, despite thousands being pasted into the console.

Here's my code:

Code:
RX:	; Receive a char in A without echoing
	PUSH	BC
	PUSH	DE
	PUSH	HL
rxl:	LD	E,0FFh		; Get char, no echo
	BDOS	C_RAWIO		; Call BDOS function 6
	JP	Z,rxl		; Loop if no char received
	POP	HL
	POP	DE
	POP	BC
	RET			; Char in A

Setting E to 0FDh would obviously be ideal, as C_RAWIO will automatically wait until a char is received and save me from the rxl: loop, but that only works in CP/M 3 apparently and I need this to work with 2.2 primarily.

Any ideas? :confused:
 
Last edited:
You might need to test register A (e.g. OR A,A). I don't think you can assume the Z bit has been set accordingly. I'm not sure what your "BDOS" macro does, but the 2.2 BDOS does not test A when returning from any function, and in the case of RAWIO is appears the Z will always be set (due to internal logic of the BDOS).
 
You might need to test register A (e.g. OR A,A). I don't think you can assume the Z bit has been set accordingly. I'm not sure what your "BDOS" macro does, but the 2.2 BDOS does not test A when returning from any function, and in the case of RAWIO is appears the Z will always be set (due to internal logic of the BDOS).

Hi durgadas!

Yes, that was the problem - I wasn't testing A. I'd misread the information on the BDOS function - it said it returns zero if no chars where available. I took that to mean it returned with the zero flag set, but actually it returns with 0 in A. :rolleyes:

Adding
Code:
OR    A
after the BDOS call to set the zero flag where relevant fixed it. ;)
 
Yeah,

Hi guys.

Read what it says, not what you think it says...

Been there, done that, got the tee shirt :)!

Dave
 
A lot of applications of the time simply bypassed the extra overhead of BDOS and vectored to the BIOS services for single-character I/O. It was marginally faster.
 
A lot of applications of the time simply bypassed the extra overhead of BDOS and vectored to the BIOS services for single-character I/O. It was marginally faster.

If it doesn't have to be portable, you can just directly read the serial port your self. If it has an interrupt driven input buffer, you'd need to disable the interrupt but most CP/M systems were simple chip status poled inputs.
Dwight
 
Ah, so that's where I went wrong with my BIOS! :) Actually, it doesn't matter if input is interrupt-driven or not.

With interrupt-driven I/O (even on the IBM PC platform), you just suck up input until you get a "no input ready) status, then grab the next character that comes by. Of course, the same code works for poll-mode input as well. It only requires a "get input status" facility.
 
Ah, so that's where I went wrong with my BIOS! :) Actually, it doesn't matter if input is interrupt-driven or not.

With interrupt-driven I/O (even on the IBM PC platform), you just suck up input until you get a "no input ready) status, then grab the next character that comes by. Of course, the same code works for poll-mode input as well. It only requires a "get input status" facility.

Interesting idea to go direct to the BIOS - might give that some consideration and bypass the BDOS completely, as I'm receiving anything from 128 bytes to 60+ KB as a pasted character stream into the terminal. Might speed the thing up a little, not that it's a great issue anyway. I'm using interrupt-driven I/O too.
 
I think you are running at 115k baud, which is about 86 usec per character. We did those calculations before, I think, when debugging problems with handshake. To stay ahead of that stream you'd have to pretty much eliminate all interface code, including the BIOS. For a specific application like sucking a huge stream of data from the console it might make sense to tune it, although you might want to consider how much effort to put into that for what it does for you. Sometimes it's better to just keep it simple and use the OS. If it were taking minutes to transfer the code, you might need to do something different. The best you could do is receive 128 characters in 11msec, but then you have to write it to the file and that's going to take much more time. I suspect the time you might save would be lost in the disk I/O.

Although, I guess you are not using traditional rotational media, so perhaps the disk I/O is not as high of overhead. Still, worth considering what you actually gain and whether it is worth the investment.
 
Last edited:
Interesting idea to go direct to the BIOS - might give that some consideration and bypass the BDOS completely, as I'm receiving anything from 128 bytes to 60+ KB as a pasted character stream into the terminal. Might speed the thing up a little, not that it's a great issue anyway. I'm using interrupt-driven I/O too.

For console I/O interrupt-driven is fine, but for serial (RS232C) streaming, interrupt latency is a big time waster. By far (we did this with 8251 for SDLC/HDLC/bisync), the best is DMA; it pretty much leaves the CPU out of the picture. Otherwise, poll-mode (but disable any higher-priority interrupts) is about as good as can be done. In any case, if you're doing disk I/O at the same time, some handshaking protocol is a must.
 
Interrupt driven I/O is only going to help if you have a big enough buffer and/or flow control.

Some of the classic xmodem and zmodem apps have overlays for differiing systems because they can't keep up otherwise. Really 115,200 is a bit too fast for a little micro. My 8Mhz box struggles at 115,200. It's also probably easier to use a tool that sends the characters one by one with delay or to use something like xmodem where you hopefully won't overrun your interrupt buffer.
 
At high bit rates, it doesn't matter what size your buffer is. The interrupt-servicing latency will be too high on a stock 2MHz Z80 system to do any good. Poll-mode is perhaps a bit better, but far from ideal. DMA is really the only good solution.
 
Well, my system is running quite happily at 4 MHz with a 125 kbaud terminal via interrupts? The ISR is pretty tight, so maybe that helps. I'm interested in knowing what this DMA solution is all about though, Chuck(G)? Can you signpost me to any information on it?
 
Well, my system is running quite happily at 4 MHz with a 125 kbaud terminal via interrupts? The ISR is pretty tight, so maybe that helps. I'm interested in knowing what this DMA solution is all about though, Chuck(G)? Can you signpost me to any information on it?

Your system would need some type of DMA controller. Most S-100 systems do not have any DMA as a general rule. They could but don't.
An example of a DMA setup would be to look at the buffer for the DigitalSystems disk controller. It does DMA for both read and write.
Dwight
 
Well, my system is running quite happily at 4 MHz with a 125 kbaud terminal via interrupts? The ISR is pretty tight, so maybe that helps. I'm interested in knowing what this DMA solution is all about though, Chuck(G)? Can you signpost me to any information on it?

You'd need to add a DMA controller in order to use DMA on the CP/M side. That would be a big change, and re-write of code, just to enhance something that already works. Typically, one would add DMA for disk devices, maybe serial ports for special cases like multi-user systems or specialized background communications.

What Dwight said...
 
If you do use interrupt-driven I/O, try to make use of the auxiliary register set in the Z80, if you're not doing it already; that can speed things up quite a bit by not needing to save and load registers.

Another approach is to have the comm controller do DMA to a small shared block of local memory. Since the DMAC and the SIO chip would be on the same board, you wouldn't depend on the bus signals to do handshake.

Just thinking aloud...
 
Last edited:
Your system would need some type of DMA controller. Most S-100 systems do not have any DMA as a general rule. They could but don't.
An example of a DMA setup would be to look at the buffer for the DigitalSystems disk controller. It does DMA for both read and write.
Dwight

Thanks Dwight - was just interested to know how it would work. I don't have a DMA in my system - was planning on putting one in, but they're not that easy to get hold of these days and, as durgadas rightly points out, there's not much point as the system works. :)

You'd need to add a DMA controller in order to use DMA on the CP/M side. That would be a big change, and re-write of code, just to enhance something that already works. Typically, one would add DMA for disk devices, maybe serial ports for special cases like multi-user systems or specialized background communications.

What Dwight said...

I'm not sure I'm at the point that I'd need a DMA just yet, but who knows? They do seem to be the hardest of the Z80 peripheral chips to get hold of these days, though.

If you do use interrupt-driven I/O, try to make use of the auxiliary register set in the Z80, if you're not doing it already; that can speed things up quite a bit by not needing to save and load registers.

Another approach is to have the comm controller do DMA to a small shared block of local memory. Since the DMAC and the SIO chip would be on the same board, you wouldn't depend on the bus signals to do handshake.

Just thinking aloud...

You know, I haven't touched IX & IY yet. Perhaps I should start looking at how they can be used and broaden my knowledge a little more.

Thanks everyone. :D
 
No, I was talking about the "ex af,af'" and "exx" instructions, that switch to AF' BC' DE' and HL' secondary registers. Very fast, with no memory references (as opposed to push and pop).
 
Back
Top