Jump to content
IGNORED

Pascal on the 99/4A


apersson850

Recommended Posts

The p-code card is still enabled when your assembly routines are called.

You have two cards on simultaneously. That's never a good idea, but you would have survived if it was only during your assembly program's execution. But you return to Pascal in between, and then you need the PME again.

 

You can for sure use the RS232 card directly from assembly under the p-code card, as long as you disable the p-code card while you do it, and re-enable it before returning to Pascal.

 

CRUPCODE .EQU 1F00H
CRURS232 .EQU 1300H

	.PROC RS232FIX

	MOV	R12,R7
	LI	R12,CRUPCODE
	SBZ	0
	LI	R12,CRURS232
	SBO	0
	SBO	7

; Play with the RS 232

	SBZ	7
	SBZ	0
	LI	R12,CRUPCODE
	SBO	0
	MOV	R7,R12
	B	*R11

 

Note the need to save R12 and restore before returning. When the PME is running, R8-R15 have values essential to the system. You can freely use R0-R7 in PASCALWS (8380H). If you need more you need to change to a different workspace.

 

Main workspace for PME(>8380)

--------------

R0-R7   Temporary use

R8      is the p-code instruction pointer.

R9      is used as a frame pointer for activation records allocated on the stack.

R10     is the stack pointer.

R11     is the return link.

R12     contains the address of the PME instruction fetch routine.

R13     contains the Read Data address of the currently executing code segment. Could be PGRMRD, VDPRD or 0 (for CPU RAM).

R14     Global data frame pointer for current segment.

R15     is a flag used to remember where the p-code currently interpreted is located.  =0: CPU RAM    <0: VDP RAM    >0: GROM

 

After the interpretation of each p-code, the PME will do a B *R12, so if that's not pointing to 8300H, you're toast.

Edited by apersson850
  • Like 2
  • Thanks 2
Link to comment
Share on other sites

Ok so I reworked the tests and still same lock up.

; routines for rs232 card access

        .proc   initrs232,1
; setup the rs232 cru address

        .def    cruadr,pmeret
        mov     *r10+,r1        ; get the desired rs232 card number
        ci      r1,1
        jne     rs2322
        li      r1,1300h
        jmp     savecru
rs2322  li      r1,1500h
savecru mov     r1,@cruadr      ; save base cru address
        b       *r11

cruadr  .word
pmeret  .word

        .proc   testbit
; test cru bit access

        .ref    cruadr,pmeret
        mov     r12,@pmeret
        li      r12,1f00h
        sbz     0
        mov     @cruadr,r12
        sbo     0
        sbo     7
        sbz     7
        sbz     0
        li      r12,1f00h
        sbo     0
        mov     @pmeret,r12
        b       *r11
        
        .end
        

 

program rs232test;
 
procedure initrs232(cardnum : integer); external;
procedure testbit; external;

begin
 page(output);
 initrs232(1);
 testbit;
end. (* rs232test *)

 

  • Thanks 1
Link to comment
Share on other sites

Oops. Looks like I had forgotten to assemble the updated version and was linking in the old version. Sorry.

Having to turn off the RS232 before returning to the pcode system definitely complicates the high-level control of the card through the use of small assembly routines like I've done for XB for example.

 

I do have a side question:

Can you BL from one .proc to another (of course saving R11 prior to the call)? I tried doing that and I got weird assembler errors where it would not recognize the .end directive (?). 

Link to comment
Share on other sites

As I responded in the assembly thread, depending on what you intend to do with the RS232 card, you may not have to turn it on. If you don't, then you don't have to turn the p-code card off either.

 

Here's a not very useful example of what you should be able to do.

 

	.PROC DUMMY1
	.DEF SUB1

		MOV	R11,R7
		LI	R1,12
		BL	@SUB1	; Call local subroutine
		CLR	R1
		B	*R7 ; Return to Pascal

SUB1		MOV	R1,R2
		B	*R11

	.PROC DUMMY2
	.REF  SUB1

		MOV	R11,R7
		LI	R1,24
		BL	@SUB1	; Call external subroutine
		CLR	R1
		B	*R7 ; Return to Pascal

	.END

 

Edited by apersson850
  • Like 2
Link to comment
Share on other sites

1 hour ago, apersson850 said:

As I responded in the assembly thread, depending on what you intend to do with the RS232 card, you may not have to turn it on. If you don't, then you don't have to turn the p-code card off either.

 

Here's a not very useful example of what you should be able to do.

 

	.PROC DUMMY1
	.DEF SUB1

		MOV	R11,R7
		LI	R1,12
		BL	@SUB1	; Call local subroutine
		CLR	R1
		B	*R7 ; Return to Pascal

SUB1		MOV	R1,R2
		B	*R11

	.PROC DUMMY2
	.REF  SUB1

		MOV	R11,R7
		LI	R1,24
		BL	@SUB1	; Call external subroutine
		CLR	R1
		B	*R7 ; Return to Pascal

	.END

 

Ah I see what I did wrong: I did not .DEF/.REF the .PROC I was calling with a BL. Thanks for the clarification. 

Apologies for all the questions. There are enough differences between regular assembly and assembly under the pcode system to throw me off old habits. I am however starting to gain a much better understanding of the pcode environment thanks to you. While the pcode assembler and linker manuals have good info, they are not nearly enough for anything more than the most basic assembly routines. 

  • Like 2
Link to comment
Share on other sites

I have spent a lot of time figuring out the things the manuals don't tell you.

My attempts to implement turtlegraphics and pre-emptive multitasking has gained me an insight into the particular p-system in the 99/4A that's probably unique among people outside of the group that developed it.

 

It feels good to be able to share with somebody who's interested.

  • Like 2
Link to comment
Share on other sites

7 hours ago, apersson850 said:

I couldn't see any reason for why that wouldn't work, so I tried it in Classic 99. Works as it should. No lockup.

Do be aware that Classic99 does not emulate DSR conflict. I think the debug log should throw a warning if it happens, though...

Link to comment
Share on other sites

3 hours ago, apersson850 said:

Well, that I caught by just reading the code.

I would have tried the real thing if we hadn't figured it out.

Out of curiosity, what does Classic 99 do if two cards are enabled at the same time? Picks a favorite one?

Most recent one, IIRC.

Link to comment
Share on other sites

On 12/9/2018 at 11:29 PM, apersson850 said:

No, there's no compiler for the UCSD p-system that produces assembly code. The SYSTEM.COMPILER in the system produces p-code. That's the whole point with the p-system, as it makes it easier to port to different computers and it makes the code more compact. The tradeoff is execution speed.

There was a native code generator for the p-system, but I've never seen any for the TI. The native code converter takes simple p-codes and convert them to assembly code, inline with the p-codes.

I read some parts from the USUS newsletters that are available form whtech. I found a passage where a possible native code generator for the 6502 processor was discussed. But it was found that the memory requirement expansion factor, when converting p-code to 6502 instructions, was about 1 to 6. That was found unrealistic at the time, so they never did any native code generator for the 6502.

 

One issue with creating one for the 9900 is that first you have to do quite a bit of support routines just to handle the code files, before you can get at actually generate any equivalent native code from the p-code.

And then you have to deal with the code files again to save your work properly, as parts of the code file are likely to grow, thus displacing other parts of the file.

 

To see if it will run probably on the TI 99/4A by simulating the whole process is probably the best start. You could simulate the native code generation by using some p_machine statements in a program.

  • Like 1
Link to comment
Share on other sites

I was browsing through the SAGE p-system Program Development manual from 1983, and although it does not specify a particular version of the p-system, it does describe a Turtlegraphics unit and a debugger. There is also SYSTEM.MENU file which can be used with applications. Of interest there is also a description of a native code generator. None of these features were included with the TI version, although we do have now a Turtlegraphics unit thanks to @apersson850. I wonder why the debugger never made it into the package...

  • Like 1
Link to comment
Share on other sites

I read an article in one issue of the USUS newsletter at whtech. The article was about the 99/4A p-system and was written by a user.

He did not claim to be an expert, not at all, but it's still interesting to see how little they knew in 1985 within USUS, compared to four of us in the Swedish group Programbiten. Since we were three p-system users just a short walk away from each other and one more 10 km away, we may have been the most dense concentration anywhere in 1983.

  • Like 3
Link to comment
Share on other sites

36 minutes ago, apersson850 said:

I read an article in one issue of the USUS newsletter at whtech. The article was about the 99/4A p-system and was written by a user.

He did not claim to be an expert, not at all, but it's still interesting to see how little they knew in 1985 within USUS, compared to four of us in the Swedish group Programbiten. Since we were three p-system users just a short walk away from each other and one more 10 km away, we may have been the most dense concentration anywhere in 1983.

Well, 41 years later and the situation does not seem to have changed much! 😁 Back then, as now, the hardware requirements to run UCSD Pascal were steep considering that most folks had bought their TI's heavily discounted towards the end of its production, while expansion hardware like the PEB, floppy drives, 32K RAM, Disk controller and RS232, not to mention a printer, remained very expensive to acquire. Your particular situation definitely was uncommon to say the least...

Link to comment
Share on other sites

3 hours ago, Vorticon said:

Well, 41 years later and the situation does not seem to have changed much! 😁 Back then, as now, the hardware requirements to run UCSD Pascal were steep considering that most folks had bought their TI's heavily discounted towards the end of its production, while expansion hardware like the PEB, floppy drives, 32K RAM, Disk controller and RS232, not to mention a printer, remained very expensive to acquire. Your particular situation definitely was uncommon to say the least...

Speaking of RS232, were you able to make any progress on that?

Link to comment
Share on other sites

Yes, they do, but I think that's because they've used a manual written for a different CPU and just edited that to fit the TMS 9900, creating several firm and soft errors along the way. By firm error I mean things that don't work, by soft things that do work but are done better in other ways using the memory-to-memory architecture of the TMS 9900.

 

Here's the example from the Linker manual, page 24. I have removed the original comments from the assembly program and instead inserted my own, pointing out what's not too clever and what's not working at all. Glance in the Linker manual page 24 in parallel to get the full picture.

My feeling is that the outline of this program comes from a description for a CPU which implements stack handling in the CPU, but doesn't have the same memory-to-memory capabilities as the TMS 9900.

 

program example;  (* Pascal host program *)
const size = 80;
var i,j,k: integer;
    lis1: array[0..9] of char;
    (* prt and lst2 get allocated here in memory when the program is running, but are declared in the assembly program using .PRIVATE *)

procedure do_nothing; external;
function null_func(xxyxx,z: integer): integer; external;

begin  (* main Pascal program *)
  do_nothing;
  j := null_func(k,size);
end. (* example *)

SP		.EQU	10		; Not in original example but adds readability
		.PROC	DONOTHING		; No parameters at all

		.CONST	SIZE		; Easy way to refernce value in host
		.PUBLIC	I,LST1		; Same for global variables
		.DEF	TEMP1		; Since .PROC, .FUNC and .END are assembly code segment delimiters, you can only access TEMP1 from between .PROC DONOTHING
							: and .FUNC NULLFUNC, unless you DEFine it for external access. DEF is implicit in .PROC, so BL @DONOTHING would be legal
							; from NULLFUNC.

		B	*R11
TEMP1	.WORD				; Still belongs to DONOTHING

		.FUNC	NULLFUNC,2		; Two parameters, but since it's an integer function, the runtime system will also allocate space for the return value on the
								; stack, prior to pushing the parameters.
		.PRIVATE	PRT,LST:9	; ERROR in the example - should be .PRIVATE  PRT,LST2:9
		.REF	TEMP1		; So we can reach TEMP1 from this side of the .FUNC NULLFUNC,2 directive

		MOV	*SP+,TEMP1		; ERROR - Should be MOV *SP+,@TEMP1
		MOV	*SP+,PRT		; ERROR - Should be MOV *SP+,@PRT
		MOV	*SP+,JUNK		; ERROR - Should be MOV *SP+,@JUNK
							; But the whole thing is unnecessary. Since the idea is to pop a value that's not used anyway, we can just as well do a INCT SP.
							; Which in turn is unnecessary too, since we don't intend to do anything with the stack prior to returning the result, so the 
							; best thing here is to simply don't do anyting at all, just leave SP pointing to where to return the result.

		MOV	LST,LST			; ERROR - Should be MOV @LST,@LST	Meaningless, but illustrates the concept of NULLFUNC
		DECT	SP			; Required only if we were stupid enough to increment the stack pointer in vain above
		MOV	LST+4,*SP		; ERROR - Should be MOV @LST+4,*SP
		B	*R11
JUNK	.WORD				; Just a waste of space if we "pop" by INCT SP, or even better, don't "pop" at all.
		.END

 

There are six lines that are in ERROR. One of those and one more could better be omitted all together.

Below is the same thing again, with all syntax errors and excessive stuff removed.

 

program example;  (* Pascal host program *)
const size = 80;
var i,j,k: integer;
    lis1: array[0..9] of char;
    (* prt and lst2 get allocated here in memory when the program is running, but are declared in the assembly program using .PRIVATE *)

procedure do_nothing; external;
function null_func(xxyxx,z: integer): integer; external;

begin  (* main Pascal program *)
  do_nothing;
  j := null_func(k,size);
end. (* example *)

SP		.EQU	10		; Not in original example but adds readability
		.PROC	DONOTHING		; No parameters at all

		.CONST	SIZE		; Easy way to refernce value in host
		.PUBLIC	I,LST1		; Same for global variables
		.DEF	TEMP1		; Since .PROC, .FUNC and .END are assembly code segment delimiters, you can only access TEMP1 from between .PROC DONOTHING
							: and .FUNC NULLFUNC, unless you DEFine it for external access. DEF is implicit in .PROC, so BL @DONOTHING would be legal
							; from NULLFUNC.

		B	*R11
TEMP1	.WORD				; Still belongs to DONOTHING

		.FUNC	NULLFUNC,2		; Two parameters, but since it's an integer function, the runtime system will also allocate space for the return value on the
								; stack, prior to pushing the parameters.
		.PRIVATE	PRT,LST2:9
		.REF	TEMP1		; So we can reach TEMP1 from this side of the .FUNC NULLFUNC,2 directive

		MOV *SP+,@TEMP1		; Pop second parameter
		MOV *SP+,@PRT		; Pop first parameter. Leave stack pointer pointing at word to return.
		MOV	@LST,@LST
		MOV	@LST+4,*SP		; Just store the result word where the SP is pointing
		B	*R11
		.END

 

The second example is more lean. But if we assume we have a CPU that can't access the value at top of stack directly, but have to POP register, modify the register and then PUSH register, then it makes sense completely. You wouldn't be able to PUSH result to the correct place without first POP junk with that limitation in stack access. Now the TMS 9900 doesn't have any predefined stack system, but the indirect register access allows us to make one.

With a very simple 8-bit architecture you may have to do something like this to add the two 16-bit numbers on top of the stack.

 

Assuming an 8-bit architecture with A being the accumulator, BC, DE and HL being 16-bit register pairs. POP and PUSH to/from register pairs is 16 bit. No direct access to top of stack.
You have to PUSH to store a value there and POP to read it.

	POP	BC
	POP	DE
	POP	HL
	MOV	B,A
	ADD D
	MOV A,B
	MOV	C,A
	ADD E
	JNC	NOCAR
	INC	B
NOCAR
	MOV	A,C
	PUSH BC

With the TMS 9900, the same thing is accomplished by 

A *SP+,*SP

 

There are frequently more advanced features in 8-bit CPU architectures too, but the principle should be clear. With this design you have to POP  before you can PUSH.

Edited by apersson850
  • Like 4
Link to comment
Share on other sites

Here's a library of assembly routines providing access to the RS232 card at the low level from the pcode environment, both serial and parallel.

Spoiler
; Routines for low-level rs232 access

pioadr  .equ    5000h

        .proc setrs232,1
; set up the rs232 card cru base
; 1 = CRU 1300H, 2 = CRU 1500H

        .def    cruadr,pmeret,procret,pcodeon,pcodoff,uartdis
        .def    rs232on,rs232of
        mov     r12,@pmeret     ;save the pme pointer
        mov     *r10+,r1        ;get desired RS232 card number
        ci      r1,1
        jne     rs2322
        li      r12,1300h
        li      r3,40h          ;uart base address displacement
        jmp     savecru
rs2322  li      r12,1500h
        li      r3,80h          ;uart base address displacement
savecru mov     r12,@cruadr     ;save base CRU address
        mov     r3,@uartdis     ;save uart base address displacement
        mov     @pmeret,r12     ;restore the pme pointer
        b       *r11
        
cruadr  .word
pmeret  .word
procret .word
uartdis .word

pcodeon li      r12,1f00h       ;activate the pcode card
        sbo     0
        mov     @pmeret,r12     ;retrieve the pme pointer
        b       *r11
        
pcodoff mov     r12,@pmeret     ;save the pme pointer
        li      r12,1f00h       ;deactivate the pcode card
        sbz     0
        b       *r11
        
rs232on mov     @cruadr,r12     ;load rs232 cru base
        sbo     0               ;turn card on
        sbo     7               ;turn card led on
        b       *r11
        
rs232of mov     @cruadr,r12     ;load rs232 cru base
        sbz     7               ;turn card led off
        sbz     0               ;turn card off
        b       *r11
        
        .proc   bitset,2
;set/reset specified cru bit


        .ref    cruadr,pmeret
        mov     r12,@pmeret     ;save the pme pointer
        mov     @cruadr,r12     ;retrieve the base cru address
        mov     *r10+,r1        ;get the cru bit state request (0 or 1)
        mov     *r10+,r2        ;get the cru bit number
        sla     r2,1            ;multiply by 2
        a       r2,r12          ;offset the cru base
        ci      r1,1
        jne     setzero
        sbo     0
        jmp     setdone
setzero sbz     0
setdone mov     @pmeret,r12     ;restore the pme pointer
        b       *r11

        .proc   sendbyte,1
;send a byte to the serial port

        .ref    pcodeon,pcodoff,rs232on,rs232of,uartdis,procret
        mov     r11,@procret
        bl      @pcodoff
        bl      @rs232on
        mov     *r10+,r6        ;get byte to send
        swpb    r6
        a       @uartdis,r12    ;set uart base address
        sbo     16              ;activate rts line. ready to send
notread tb      27              ;test dsr pin. is receiver ready?
        jne     notread
notempt tb      22              ;is emission buffer empty?
        jne     notempt
        ldcr    r6,8            ;send byte
        sbz     16              ;inactivate rts line. not ready to send
        bl      @rs232of
        bl      @pcodeon
        mov     @procret,r11
        b       *r11
        
        .proc   hskout,1
;set handshakeout line (0 or 1)

        .ref    pcodeon,pcodoff,rs232on,rs232of,procret
        mov     r11,@procret
        bl      @pcodoff
        bl      @rs232on
        mov     *r10+,r6        ;get requested state of hskout line
        ci      r6,1
        jne     hskolow
        sbo     2               ;set hskout line to high
        jmp     hskoret
hskolow sbz     2               ;set hskout line to low
hskoret bl      @rs232of
        bl      @pcodeon
        mov     @procret,r11
        b       *r11
        
        .proc   sprout,1
;set spareout line (0 or 1)

        .ref    pcodeon,pcodoff,rs232on,rs232of,procret
        mov     r11,@procret
        bl      @pcodoff
        bl      @rs232on
        mov     *r10+,r6        ;get requested state of sprout line
        ci      r6,1
        jne     sprolow
        sbo     3               ;set sprout line to high
        jmp     sproret
sprolow sbz     3               ;set sprout line to low
sproret bl      @rs232of
        bl      @pcodeon
        mov     @procret,r11
        b       *r11
        
        .proc   datout,1
;send a byte to the pio port

        .ref    pcodeon,pcodoff,rs232on,rs232of,procret
        mov     r11,@procret
        bl      @pcodoff
        bl      @rs232on
        mov     *r10+,r6        ;get the byte to send
        swpb    r6
        sbz     1               ;set port to output
        movb    r6,@pioadr      ;send byte
        bl      @rs232of
        bl      @pcodeon
        mov     @procret,r11
        b       *r11
        
        .func   getbyte
;receive a byte from the serial port
        
        .ref    pcodeon,pcodoff,rs232on,rs232of,uartdis,procret,cruadr
        mov     r11,@procret
        bl      @pcodoff
        bl      @rs232on
        sbz     5               ;activate cts line. ready to receive
        a       @uartdis,r12    ;uart base cru address
chkdsr  tb      27              ;test dsr pin. signal is inverted!
        jne     chkdsr          ;if line high then not ready
chkbuf  tb      21              ;test receive buffer
        jne     chkbuf
        stcr    r6,8            ;get byte into r6
        sbz     18              ;reset buffer cru bit 21
        swpb    r6
        sbo     -27             ;inactivate cts line. cru 5 disp from 1340h
        mov     r6,*r10         ;place byte on return stack
        bl      @rs232of
        bl      @pcodeon
        mov     @procret,r11
        b       *r11
        
        .func   datin
 ;get byte from pio port
 
        .ref    pcodeon,pcodoff,rs232on,rs232of,procret
        mov     r11,@procret
        bl      @pcodoff
        bl      @rs232on
        sbo     1               ;set port to input
        clr     r6
        movb    @pioadr,r6      ;get byte from port
        swpb    r6
        mov     r6,*r10         ;save byte to return stack
        bl      @rs232of
        bl      @pcodeon
        mov     @procret,r11
        b       *r11
        
        .func   hskin
;get status of handshakein line
 
        .ref    pcodeon,pcodoff,rs232on,rs232of,procret
        mov     r11,@procret
        bl      @pcodoff
        bl      @rs232on
        tb      2               ;get logic state of hskin line
        jne     hskilow
        li      r6,1
        jmp     hskiret
hskilow clr     r6
hskiret mov     r6,*r10         ;save hskin state to return stack
        bl      @rs232of
        bl      @pcodeon
        mov     @procret,r11
        b       *r11
        
        .func   sprin
;get status of sparein line

        .ref    pcodeon,pcodoff,rs232on,rs232of,procret
        mov     r11,@procret
        bl      @pcodoff
        bl      @rs232on
        tb      3               ;get logic state of sparein line
        jne     sprilow
        li      r6,1
        jmp     spriret
sprilow clr     r6
spriret mov     r6,*r10         ;save sprin state to return stack
        bl      @rs232of
        bl      @pcodeon
        mov     @procret,r11
        b       *r11
        
        .end

 

 

Here's a little program demonstrating the parallel port interfacing functionality:

program piotest;

var
 n, i : integer;
 
procedure setrs232(base : integer); external;
procedure datout(n : integer); external;
procedure hskout(n : integer); external;
procedure sprout(n : integer); external;

procedure delay;
var
 d : integer;
 
begin
 for d := 1 to 100 do
end;

begin
 setrs232(1);
 for i := 1 to 20 do
  begin
   n := 1;
   repeat
    begin
     hskout(1);
     delay;
     hskout(0);
     datout(n);
     delay;
     sprout(1);
     delay;
     sprout(0);
     n := n * 2;
    end;
   until n > 256;
  end
end.
   

 

and here it is in action

 

 

With this library, you should be able to interface the TI to a variety of real world projects using pcode. I should state that I've done something similar for XB, but with the latter assembly routines access is much slower whereas within the pcode environment I had to actually introduce delays.

Next is XMODEM :)

 

  • Like 4
Link to comment
Share on other sites

Congratulations.  This looks really good.  I found an Xmodem program in Forth, of all things,  but it might take some effort to port it.

It was written for PC based GForth, a far cry from a TI-99. 

I suspect you will have something going pretty quickly with your new solid RS232 library and that Pcode system. 

 

 

  • Like 3
Link to comment
Share on other sites

I was reading your Asm code to send a byte and I see something that won't bite you until you try sending to another slow computer that uses RTS/CTS handshaking.

 

The DSR/DTR is typically used to indicate that a "data set" and a "data terminal" are connected. 

Now you can find devices that use it to throttle data but my understanding is that is not what it is for. 

 

The RTS/CTS lines are "supposed" to be for throttling data and preventing overruns. 

This is what Teraterm does for example.  Now when a TI-99 sends bytes to a modern PC it's probably never going to overrun it. :) 

But if you were sending to another retro-computer it might matter if that program has proper RTS/CTS handshaking and debugging those problems is a pain.

 

So when you send a byte, you test DSR to make sure everybody is connected. You got that.

 

Then the SENDER sets the RTS line and WAITS for the receiver to reply with the CTS.

It's a question and answer type protocol.

Sender: I am ready to send. 

Receiver: OK,  you are clear to send

 

So here what I think you need based what I have learned in my little dungeon.

        .proc   sendbyte,1
;send a byte to the serial port

        .ref    pcodeon,pcodoff,rs232on,rs232of,uartdis,procret
        mov     r11,@procret
        bl      @pcodoff
        bl      @rs232on
        mov     *r10+,r6        ;get byte to send
        swpb    r6
        a       @uartdis,r12    ;set uart base address

notread tb      27              ;test dsr pin. Are we connected?
        jne     notread
        
        sbo     16              ;activate rts line. ready to send
waitcts tb      28 
        jne     waitcts 
        
notempt tb      22              ;is emission buffer empty?
        jne     notempt
        ldcr    r6,8            ;send byte
        sbz     16              ;inactivate rts line. not ready to send
        bl      @rs232of
        bl      @pcodeon
        mov     @procret,r11
        b       *r11

 

 

 

And one minor change to minimize the chance of losing a character on receive is to give the permission to send immediately before you start looking for it. 

 

       .func   getbyte
;receive a byte from the serial port
        
        .ref    pcodeon,pcodoff,rs232on,rs232of,uartdis,procret,cruadr
        mov     r11,@procret
        bl      @pcodoff
        bl      @rs232on
 
        a       @uartdis,r12    ;uart base cru address
chkdsr  tb      27              ;test dsr pin. signal is inverted!
        jne     chkdsr          ;if line high then not ready

; pull -CTS line right before the code tests the receive buffer         
        sbz     -27             ;activate cts line. ready to receive

chkbuf  tb      21              ;test receive buffer
        jne     chkbuf
        stcr    r6,8            ;get byte into r6
        sbz     18              ;reset buffer cru bit 21
        swpb    r6
        sbo     -27             ;inactivate cts line. cru 5 disp from 1340h
        mov     r6,*r10         ;place byte on return stack
        bl      @rs232of
        bl      @pcodeon
        mov     @procret,r11
        b       *r11

 

And of course you can add flag variables that that let you enable or disable either or both handshake tests,

but for receive the 99 really needs to throttle the sending machine.

(until you get @InsaneMultitasker 's  interrupt driven receive running) ;)

 

 

  • Like 3
  • Thanks 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...