New modular design 65c816 based with Supermon816

For discussing the 65xx hardware itself or electronics projects.
leepivonka
Posts: 168
Joined: 15 Apr 2016

Re: New modular design 65c816 based with Supermon816

Post by leepivonka »

at 403a: error -----------------------------------------------
403a & 403f don't wrap the same way as at 40f1 - it'll go to values that the interrupt handler can never get to.
The interrupt handler will keep retransmitting old bytes trying to get there.

at 4012: error ------------------------------------------------
4012 doesn't wrap the same way as at 40c1,

comment -------------------------------------------------------
Do nx_rx_get_a, nx_tx_get_a, nx_rx_put_a, nx_tx_put_a get initialized somewhere not shown?
If they have random values at startup, you'll get random characters received & transmitted when you start up.

at nx_irq: error? ---------------------------------------------
Interrupted routine's registers need to be saved before this code executes - is this just not shown?
It should be the reverse of the register restores at nx_irq_end: . )

at 4099: comment ------------------------------------------------
This doesn't match the stack contents here.
DP is 2byte.
Hardware pushes P (SR), then PBR, then PC.

; stack now contains
; +13 saved CPU status register
; +12 saved program bank
; +10 saved PC
; +09 saved data bank
; +07 saved DPR
; +05 saved A
; +03 saved X
; +01 saved Y


comment ---------------------------------------------------------------------
I think this UART has rx & tx FIFOs more than 1 byte deep. You could process multiple bytes in the interrupt routines if you want them to use less CPU time.
xjmaas
Posts: 41
Joined: 03 May 2016

Re: New modular design 65c816 based with Supermon816

Post by xjmaas »

Thank you for the feedback!
leepivonka wrote:
at 403a: error -----------------------------------------------
403a & 403f don't wrap the same way as at 40f1 - it'll go to values that the interrupt handler can never get to.
The interrupt handler will keep retransmitting old bytes trying to get there.

at 4012: error ------------------------------------------------
4012 doesn't wrap the same way as at 40c1,
I was already suspecting it had something to do with the index wrapping?
leepivonka wrote:
Do nx_rx_get_a, nx_tx_get_a, nx_rx_put_a, nx_tx_put_a get initialized somewhere not shown?
If they have random values at startup, you'll get random characters received & transmitted when you start up.
I set them to zero in the nx_init routine at $410b:

Code: Select all

00410B  2  A2 00           ldx   #$00
00410D  2               @nextAddr:
00410D  2  74 20           stz   nx_zeropage, X
00410F  2  E8              inx
004110  2  E0 20           cpx   #$20         ; Reserve $20 (32) bytes and clear these
004112  2  D0 F9           bne   @nextAddr
leepivonka wrote:
at nx_irq: error? ---------------------------------------------
Interrupted routine's registers need to be saved before this code executes - is this just not shown?
It should be the reverse of the register restores at nx_irq_end: . )
The registers are pushed/saved in the IRQ routine higher in ROM

Code: Select all

00FDB3  2               handler_nirq:
00FDB3  2  8B           	phb				; Save current DB
00FDB4  2  0B           	phd				; Save current DP
00FDB5  2  C2 30        	longr				; 16-bit registers
00FDB7  2  48           	pha				; Save .A, .X and .Y
00FDB8  2  DA           	phx
00FDB9  2  5A           	phy
00FDBA  2               ;-----------------------
00FDBA  2               ;	Contents of stack
00FDBA  2               ;
00FDBA  2               ;irq_yreg	= 1			; 16 bit .Y
00FDBA  2               ;irq_xreg	= irq_yreg + s_word	; 16 bit .X
00FDBA  2               ;irq_areg	= irq_xreg + s_word	; 16 bit .A
00FDBA  2               ;irq_dpreg	= irq_areg + s_word	; DP
00FDBA  2               ;irq_dbreg	= irq_dpreg + s_mpudpx	; DBR
00FDBA  2               ; pushed by hardware
00FDBA  2               ;irq_srreg	= irq_dbreg + s_mpudbx	; SR
00FDBA  2               ;irq_pcreg	= irq_srreg + s_mpusrx	; PC
00FDBA  2               ;irq_pbreg	= irq_pcreg + s_mpupcx	; PBR
00FDBA  2               ;-----------------------
00FDBA  2  6C D8 02     	jmp	(VECTOR_INT)		; Jump to (indirect) vector
leepivonka wrote:
This doesn't match the stack contents here.
DP is 2byte.
Hardware pushes P (SR), then PBR, then PC.

; stack now contains
; +13 saved CPU status register
; +12 saved program bank
; +10 saved PC
; +09 saved data bank
; +07 saved DPR
; +05 saved A
; +03 saved X
; +01 saved Y
Doesn't the 65816 not first push the Program bank register, PC and last Processor Status register?
leepivonka wrote:
I think this UART has rx & tx FIFOs more than 1 byte deep. You could process multiple bytes in the interrupt routines if you want them to use less CPU time.
This is something I want to look into later on....
User avatar
BigDumbDinosaur
Posts: 9426
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: New modular design 65c816 based with Supermon816

Post by BigDumbDinosaur »

leepivonka wrote:
Hardware pushes P (SR), then PBR, then PC.

You've got that backward. Following any interrupt, PB is the first register to be pushed, followed by PC high, PC low and lastly SR. After SR has been pushed the I bit in SR is set and the D bit in SR is cleared.

Reference:
Investigating 65C816 Interrupts
x86?  We ain't got no x86.  We don't NEED no stinking x86!
User avatar
BigDumbDinosaur
Posts: 9426
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: New modular design 65c816 based with Supermon816

Post by BigDumbDinosaur »

xjmaas wrote:
It seems that when sending data, the send buffer will not wrap. First, when I had half page buffers, receiving seemed to fill the buffers like they should. But when trying to send data, it fills to the size of the buffer (I can see that when examining the buffers after a reset), but the routine will hang there....
(I have to say, I use a regular UART cable from my 6522 based card, but an Arduino as serial emulator (with RTS and CTS tied together) to the 28L92 based card))

In the following line of code:

Code: Select all

buf_idx_mask   = s_e32_buf ^ %11111111   ; Buffer index wrap mask
change the equate to:

Code: Select all

buf_idx_mask   = s_e32_buf -1            ; Buffer index wrap mask
and set s_e32_buf to 128. Re-assemble with index wrapping enabled and see what happens.

Also, attached is the listing output from the assembly of POC V1.2's firmware. The DUART channel interrupt code starts at line 3884. Illustrated are several concepts, one being how to handle multiple channels in a loop and how to work with the DUART's FIFOs. In particular, I use an array of direct page pointers to access the hardware, queues and a transmitter status bit field, using the channel number (0-3) as an index.

aout.txt
POC V1.2 Firmware Assembly Listing
(594.52 KiB) Downloaded 40 times
x86?  We ain't got no x86.  We don't NEED no stinking x86!
xjmaas
Posts: 41
Joined: 03 May 2016

Re: New modular design 65c816 based with Supermon816

Post by xjmaas »


Hmm, "index" wrapping" seems to work. When I try to send a string several times, I can see the index wraps. But when I try to send >128 bytes, it looks like a (new) interrupt interrupts the interrupt?
(Did I mention I use 19k2 8N1 for serial?)

Next step is looking at "easier/nicer" way to drive the 'L92 using ZP indexing :)

frontend routine

Code: Select all

;-------------------------------------------------------------------------------
; Process Transmit Request
;
; Call the subroutine and the routine will try to "put" a datum into the
; corresponding TxQ. If this succeeds, the routine will return:
;	carry	- clear
;
; NOTE: Carry will be set, if the driver hasn't been initialized,
;	yet...
;-------------------------------------------------------------------------------
; nx_sioput_a - Process datum for channel A TxQ
;-----------------------
nx_sioput_a:
	shortr				; 8 bit registers
	sec				; Default, assume error
	bit	IOBASE + dr_misc	; Read bit 7 of dr_misc, if set, driver
					; has been initialized
	bpl	@done			; No, error!
;
	pha				; Preserve .A
	phx				; Preserve .X
;
	xba				; Save datum to .B
;	
	lda	nx_tx_put_a		; Get TxD "put" index
	ina				; Increment "put" index
	and	#buf_idx_mask		; Deal with wrap
;
@full:					; Loop here until there is space in TxQ
	cmp	nx_tx_get_a		; TxQ "get" index
	beq	@full			; TxQ is full, block...
;
	ldx	nx_tx_put_a
	xba				; Restore datum in .A, save new "put"
	sta	nx_tx_qa, X		; Put datum into TxQ
	xba				; Retrieve new "put" index from .B
	sta	nx_tx_put_a
;---------------
;	Manage transmitter
;---------------
	lda	#nx_txa_dis		; Transmitter disabled flag
	trb	IOBASE + dr_misc	; is transmitter disabled?
	beq	@cleanup		; No

	lda	#nx_cr_tx_ena		; Yes, enable transmitter
	sta	IOBASE + dr_cra
;
@cleanup:
	plx
	pla
	clc
;
@done:
	rts

interrupt excerpt handling TxQ

Code: Select all

;-----------------------	
; Test for channel A THR IRQ
;-----------------------
test_thr_a:
	lda	irq_isrx, S		; Get ISR from stack
;
	bit	#msk_irq_txa		; Did Xmitter A request interrupt?
	beq	test_thr_b		; Nope, try Xmitter B
;-----------------------	
; Process channel A THR IRQ
;-----------------------	
@handle_thr_a:
	ldx	nx_tx_get_a		; Buffer "get" index
	cpx	nx_tx_put_a		; Compare with buffer "put" index
	bne	@get_datum
;
	lda	#nx_cr_tx_dis		; Disable TxD to suppress ...
	sta	IOBASE + dr_cra		; ... interrupts
	lda	#nx_txa_dis		; Set xmitter disabled flag in
	tsb	IOBASE + dr_misc	; - MISC register
	tsb	nx_tx_status		; - ZP (for debug)
	bra	test_thr_b		; Buffer is empty, so we can continue
;
@get_datum:
	lda	nx_tx_qa, X		; Get datum from buffer
	sta	IOBASE + dr_txfifoa	; Write to THR
	txa				; Current position
	ina				; New buffer position
	and	#buf_idx_mask		; Deal with wrap of index
	sta	nx_tx_get_a		; Set new "get" index

User avatar
BigDumbDinosaur
Posts: 9426
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: New modular design 65c816 based with Supermon816

Post by BigDumbDinosaur »

xjmaas wrote:
Hmm, "index" wrapping" seems to work. When I try to send a string several times, I can see the index wraps. But when I try to send >128 bytes, it looks like a (new) interrupt interrupts the interrupt?

Assuming that new IRQ is coming from the DUART, it is likely because you are not completely filling the THR on each IRQ. Each time the transmitter interrupts you need to "stuff" the THR to at least the level configured by MR0 bits 3, 4 and 5 in order to clear the TxD IRQ. Writing one datum and moving on isn't how to do it, as the TxD IRQ will keep coming until you satisfy the FIFO fill level or disable the transmitter.

Please review the material in Driving the NXP 28L91 (attached), starting at page 31. If you follow the flow chart and code example it should work.

28l91_driving.pdf
Driving the NXP 28L91 UART—also applicable to the 28L92
(573.32 KiB) Downloaded 84 times
x86?  We ain't got no x86.  We don't NEED no stinking x86!
xjmaas
Posts: 41
Joined: 03 May 2016

Re: New modular design 65c816 based with Supermon816

Post by xjmaas »

Did a few extra testing and found that when I:
  • try to send <= 256 bytes, it works as expected
  • try to send > 256 bytes, the "@handle_thr_a" keeps looping somewhere...
This tells me that I have some bit in the SR set, but should be cleared? Which affects one or two branch conditions?


Code: Select all

0040E7  2               ;-----------------------
0040E7  2               ; Process channel A THR IRQ
0040E7  2               ;-----------------------
0040E7  2               @handle_thr_a:
0040E7  2               ;	ldx	nx_tx_get_a		; Buffer "get" index
0040E7  2               ;	cpx	nx_tx_put_a		; Compare with buffer "put" index
0040E7  2               ;	bne	@get_datum
0040E7  2               ;
0040E7  2               ;	lda	#nx_cr_tx_dis		; Disable TxD to suppress ...
0040E7  2               ;	sta	IOBASE + dr_cra		; ... interrupts
0040E7  2               ;	lda	#nx_txa_dis		; Set xmitter disabled flag in
0040E7  2               ;	tsb	IOBASE + dr_misc	; - MISC register
0040E7  2               ;	tsb	nx_tx_status		; - ZP (for debug)
0040E7  2               ;	bra	test_thr_b		; Buffer is empty, so we can continue
0040E7  2               ;
0040E7  2               ;@get_datum:
0040E7  2               ;	lda	nx_tx_qa, X		; Get datum from buffer
0040E7  2               ;	sta	IOBASE + dr_txfifoa	; Write to THR
0040E7  2               ;	txa				; Current position
0040E7  2               ;	ina				; New buffer position
0040E7  2               ;	and	#buf_idx_mask		; Deal with wrap of index
0040E7  2               ;	sta	nx_tx_get_a		; Set new "get" index
0040E7  2               ;
0040E7  2               ; vvvv  THIS WAS BASED ON PDF BY BDD  vvv
0040E7  2  A6 26        	ldx	nx_tx_get_a		; Get current TxQ "get" index
0040E9  2  A0 04        	ldy	#msk_sr_tx_rdy		; THR status mask
0040EB  2               ;-----------------------
0040EB  2               ; Enter the loop to service the THR interrupt. This loop will continue until
0040EB  2               ; the THR is full or TxQ is empty
0040EB  2               ;-----------------------
0040EB  2               @next_datum:
0040EB  2  E4 28        	cpx	nx_tx_put_a		; Any (new) datums in TxQ?
0040ED  2  F0 13        	beq	@tx_off			; Nope, shutdown Xmitter and go to B
0040EF  2               ;
0040EF  2  98           	tya				; YES ...
0040F0  2  2C 01 C4     	bit	IOBASE + dr_sra		; Any space left in THR
0040F3  2  F0 19        	beq	@done			; no, done for now...
0040F5  2               ;-----------------------
0040F5  2               ; If the THR is full, the transmitter IRQ processing is done for now...
0040F5  2               ; Later on, when the THR's level has been reduced, another IRQ will occur and
0040F5  2               ; more datums can be processed
0040F5  2               ;-----------------------
0040F5  2  BD 80 20     	lda	nx_tx_qa, X		; Get datum from queue and ...
0040F8  2  8D 03 C4     	sta	IOBASE + dr_txfifoa	; ... write to THR (FIFO)
0040FB  2               ;	inx				; Increment "get" index
0040FB  2  8A           	txa				; Move .X to .A
0040FC  2  1A           	inc	a			; Increment "get" index
0040FD  2  29 7F        	and	#buf_idx_mask		; Deal with wrap?
0040FF  2  AA           	tax				; move .A back to .X
004100  2  80 E9        	bra	@next_datum		; And process next
004102  2               ;
004102  2               @tx_off:
004102  2  A9 08        	lda	#nx_cr_tx_dis		; Shutdown Xmitter A to suppress ...
004104  2  8D 02 C4     	sta	IOBASE + dr_cra		; ... IRQs
004107  2  A9 40        	lda	#nx_txa_dis		; Set Xmitter A disabled flag
004109  2  0C 0C C4     	tsb	IOBASE + dr_misc	; Do in MISC register!
00410C  2  04 2D        	tsb	nx_tx_status		; And in ZP (for debug)
00410E  2               ;
00410E  2               @done:
00410E  2  86 26        	stx	nx_tx_get_a		; Save final TxQ "get" index
004110  2               ; ^^^  THIS WAS BASED ON PDF BY BDD  ^^^

User avatar
BigDumbDinosaur
Posts: 9426
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: New modular design 65c816 based with Supermon816

Post by BigDumbDinosaur »

xjmaas wrote:
Did a few extra testing and found that when I:
  • try to send <= 256 bytes, it works as expected
  • try to send > 256 bytes, the "@handle_thr_a" keeps looping somewhere...
This tells me that I have some bit in the SR set, but should be cleared? Which affects one or two branch conditions?

Code: Select all

0040E7  2               ;-----------------------
0040E7  2               ; Process channel A THR IRQ
0040E7  2               ;-----------------------
0040E7  2               @handle_thr_a:
0040E7  2  A6 26                ldx nx_tx_get_a             ; Get current TxQ "get" index
0040E9  2  A0 04                ldy #msk_sr_tx_rdy          ; THR status mask
0040EB  2               ;-----------------------
0040EB  2               ; Enter the loop to service the THR interrupt. This loop will continue until
0040EB  2               ; the THR is full or TxQ is empty
0040EB  2               ;-----------------------
0040EB  2               @next_datum:
0040EB  2  E4 28                cpx nx_tx_put_a             ; Any (new) datums in TxQ?
0040ED  2  F0 13                beq @tx_off                 ; Nope, shutdown Xmitter and go to B
0040EF  2               ;
0040EF  2  98                   tya                         ; YES ...
0040F0  2  2C 01 C4             bit IOBASE + dr_sra         ; Any space left in THR
0040F3  2  F0 19                beq @done                   ; no, done for now...
0040F5  2               ;-----------------------
0040F5  2               ; If the THR is full, the transmitter IRQ processing is done for now...
0040F5  2               ; Later on, when the THR's level has been reduced, another IRQ will occur and
0040F5  2               ; more datums can be processed
0040F5  2               ;-----------------------
0040F5  2  BD 80 20             lda nx_tx_qa, X             ; Get datum from queue and ...
0040F8  2  8D 03 C4             sta IOBASE + dr_txfifoa     ; ... write to THR (FIFO)
0040FB  2  8A                   txa                         ; Move .X to .A
0040FC  2  1A                   inc a                       ; Increment "get" index
0040FD  2  29 7F                and #buf_idx_mask           ; Deal with wrap?
0040FF  2  AA                   tax                         ; move .A back to .X
004100  2  80 E9                bra @next_datum             ; And process next
004102  2               ;
004102  2               @tx_off:
004102  2  A9 08                lda #nx_cr_tx_dis           ; Shutdown Xmitter A to suppress ...
004104  2  8D 02 C4             sta IOBASE + dr_cra         ; ... IRQs
004107  2  A9 40                lda #nx_txa_dis             ; Set Xmitter A disabled flag
004109  2  0C 0C C4             tsb IOBASE + dr_misc        ; Do in MISC register!
00410C  2  04 2D                tsb nx_tx_status            ; And in ZP (for debug)
00410E  2               ;
00410E  2               @done:
00410E  2  86 26                stx nx_tx_get_a             ; Save final TxQ "get" index
For legibility purposes, I removed the commented-out code and extra whitespace between mnemonics and operands, and reduced text size. BTW, all datums in TxQ are "new." :D

I'm not seeing anything here that would cause a loop on handle_thr_a. You said it's "looping somewhere." Any idea where "where" might be? It would be useful if you posted the entire ISR as a text file, with commented-out code removed and tabs converted to spaces. Debugging code fragments often isn't productive in this environment.
x86?  We ain't got no x86.  We don't NEED no stinking x86!
xjmaas
Posts: 41
Joined: 03 May 2016

Re: New modular design 65c816 based with Supermon816

Post by xjmaas »

BigDumbDinosaur wrote:
For legibility purposes, I removed the commented-out code and extra whitespace between mnemonics and operands, and reduced text size. BTW, all datums in TxQ are "new." :D
I will change this comment ;)
BigDumbDinosaur wrote:
I'm not seeing anything here that would cause a loop on handle_thr_a. You said it's "looping somewhere." Any idea where "where" might be? It would be useful if you posted the entire ISR as a text file, with commented-out code removed and tabs converted to spaces. Debugging code fragments often isn't productive in this environment.
I have the source for the ISR, the frontend, the assembly listing and a "test" program added.
In the test program, after uploading using the HEX loader, I change the address from which the test is loaded, manually for testing. (The $3100 is just a placeholder)
Attachments
nxp28l9x.zip
ISR, frontend, assembly listing and "test" program
(16.18 KiB) Downloaded 45 times
xjmaas
Posts: 41
Joined: 03 May 2016

Re: New modular design 65c816 based with Supermon816

Post by xjmaas »

Oh, I think i May have found the issue with (longer) strings! Going to try to rewrite your (BDD) sprint routine for the DUART
xjmaas
Posts: 41
Joined: 03 May 2016

Re: New modular design 65c816 based with Supermon816

Post by xjmaas »

I created a new debug.asm, in which I implemented the sprint functionality, but pointing to the DUART routine(s). Up to 256 bytes are sent correctly, but when I want to send > 256 bytes, the routine doesn't seem to return...


Code: Select all

        .org    $3000
        .p816

; macros
        .macro  longi                   ; Set .X and .Y to 16-bit
        rep     #%00010000
        .i16
        .endmacro
        
        .macro  shorti                  ; Set .X and .Y to 8-bit
        sep     #%00010000
        .i8
        .endmacro
        
        .macro  longa                   ; Set .A to 16-bit
        rep     #%00100000              
        .a16
        .endmacro
        
        .macro  shorta                  ; Set .A to 8-bit
        sep     #%00100000
        .a8
        .endmacro
        
        .macro  longr                   ; Set all registers to 16-bit
        rep     #%00110000              ; Set 16-bit .A, .X and .Y
        .a16
        .i16
        .endmacro
        
        .macro  shortr                  ; Set all registers to 8-bit
        sep     #%00110000              ; Set 8-bit .A, .X and .Y
        .a8
        .i8
        .endmacro
;
; Equates
nx_sioput_a     = $402e 
;
; Actual code start
start:
        shortr
        pea     large                   ; Push pointer to sting to stack
        jsr     sprint                  ; print string @ pointer on stack
@end:
        rts                             ; And.... The END...

; For a description of the routine, see source of Adria (or Supermon 816)
sprint:
        shorta
        longi
;-------
@retadd = 1                             ; Return address
@src    = @retadd + 2                   ; String address (= return address + 2)
;-------        
        ldy     #$0000
        clc                             ; Initial no error
@next:
        lda     (@src, S), Y            ; Get a byte from the string, where:
                                        ; stack pointer + 2, indexed with Y
        beq     @done                   ; If $00, we reached EOL (End-Of-Line)
;
        jsr     nx_sioput_a             ; Print character to DUART channel A
        iny                             ; increment index
        bpl     @next                   ; Continue if .Y < ($ffff + 1)
;       
        sec                             ; String is too long
;
@done:
        plx                             ; Pull return address from stack
        ply                             ; Pull string pointer from stack
        phx                             ; Push return address (in effect to 
                                        ; clear string pointer)
        shorti
        rts                             ; Done
;
; small large string (16 bytes)
small:
        .byte   "Dit is een strng"
        .byte   $0a, $0d, $00   
;
; large string (128 bytes)
large:
        .byte   "Dit is een strng"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abc"
        .byte   $0a, $0d, $00   
;
; even larger string (256 bytes)
larger:
        .byte   "Dit is een strng"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abc"
        .byte   $0a, $0d, $00   
;
; Exceed even larger string (259 bytes!)
huge:
        .byte   "Dit is een strng"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   "0123456789abcdef"
        .byte   $0a, $0d, $00   

xjmaas
Posts: 41
Joined: 03 May 2016

Re: New modular design 65c816 based with Supermon816

Post by xjmaas »

xjmaas wrote:
I created a new debug.asm, in which I implemented the sprint functionality, but pointing to the DUART routine(s). Up to 256 bytes are sent correctly, but when I want to send > 256 bytes, the routine doesn't seem to return...
I think I found the issue. Has nothing to do with the ISR or frontend code.... It was the calling code (the sprint routine)!

As we call the front end to send the byte(s), the registers are all set to 8 bit. But the index .Y for the string in sprint expects 16-bit width. What I have done, is add a PHY before and a PLY after the JSR to the frontend. Also I force the register widths just before the PLY.


Code: Select all

        beq     @done                   ; If $00, we reached EOL (End-Of-Line)
;
        phy
;
        jsr     nx_sioput_a             ; Print character to DUART channel A
        longi                           ; Force proper register widths
        shorta
        ply
        iny                             ; increment index
        bpl     @next                   ; Continue if .Y < ($ffff + 1)
       


Next step: implement into ROM and say goodbye (for now) to the 6551 ;)
xjmaas
Posts: 41
Joined: 03 May 2016

Re: New modular design 65c816 based with Supermon816

Post by xjmaas »

For those interested, I have attached the driver that is currently working for my board, for only one channel (as I need only on right now)
Please read the comment in NXP28L92.asm.

I use a cc65 build-environment and use the following commands:

Code: Select all

$path_to/cc65 -l driver.lst -o driver.o NXP28L92.asm
$path_to/ld65 -C $path_to_used_config -o driver.bin driver.o
I used the ca65/ld65 approach as using cl65 directly gives me PETSCII instead of ASCII?

Next step is to get my Intel Hex Uploader working again, as I don;t have a proper blocking uart_input right now?
Attachments
NXP28L92.zip
(22.8 KiB) Downloaded 42 times
User avatar
BigDumbDinosaur
Posts: 9426
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: New modular design 65c816 based with Supermon816

Post by BigDumbDinosaur »

xjmaas wrote:
For those interested, I have attached the driver that is currently working for my board, for only one channel (as I need only on right now)

In your foreground and interrupt code (ISR) for handling the transmitter I see you are wrapping the TxD queue at 128 bytes and have also defined TXQ at that size. I don't see wrapping occurring in the receiver's foreground and ISR. However, you are also defining RXQ as being 128 bytes.

Also, in foreground code in which you are waiting for a datum to become available (receive), or waiting for queue space to become available (transmit), you can gain a little interrupt performance by using the WAI instruction to stall the MPU instead of spinning in a loop. With the MPU WAIting in that fashion there will be no hardware interrupt latency when the DUART reports in—response time to an IRQ will not be more than one Ø2 cycle. Here's a code excerpt from my POC V1.2 BIOS that illustrates using WAI to block until TXQ space becomes available:

Code: Select all

;================================================================================
;
;putchcom: WRITE DATUM TO TIA-232 CHANNEL (common to all channels)
;
;	————————————————————————————————————————————————————————————————————————
;	Do not directly call this function, as the stack will become unbalanced.
;	Only use the PUTCHx functions, where x is the comm port ID.
;	————————————————————————————————————————————————————————————————————————
;
putchcom phy                   ;preserve...
         pha                   ;remaining registers
         phd
         pea #kerneldp
         pld                   ;set kernel direct page
         shortr
         xba                   ;protect datum
         txa                   ;channel index...
         asl                   ;becomes...
         tax                   ;channel offset
         lda tiaputtx,x        ;queue "put" index
         ina                   ;bump it &...
         and #m_tiaptr         ;mask to queue size
         ora tiaqpmsk,x        ;align to queue base addr
;
.main    cmp tiagettx,x        ;room in the queue?
         beq .qfull            ;no, wait
;
         xba                   ;swap queue pointer w/datum
         sta (tiaputtx,x)      ;put datum in queue
         xba                   ;new queue pointer
         sta tiaputtx,x        ;save it
         lda tiatstab,x        ;channel's TxD status mask
         trb tiatxst           ;transmitter running?
         bne .enabltx          ;no, enable it
;
.done    longr
         pld                   ;restore MPU status
         pla
         ply
         plx
         plp
         clc
         rts
;
;
;	block for TXQ space...
;
.qfull   wai                   ;wait for interrupt &...
         bra .main             ;try again
;
;
;	enable transmitter...
;
.enabltx lda #nxpcrtxe
         sta (tiacr,x)
         bra .done
;
x86?  We ain't got no x86.  We don't NEED no stinking x86!
xjmaas
Posts: 41
Joined: 03 May 2016

Re: New modular design 65c816 based with Supermon816

Post by xjmaas »

BigDumbDinosaur wrote:
In your foreground and interrupt code (ISR) for handling the transmitter I see you are wrapping the TxD queue at 128 bytes and have also defined TXQ at that size. I don't see wrapping occurring in the receiver's foreground and ISR. However, you are also defining RXQ as being 128 bytes.
Thank you for the extra eyes! That was something I missed and fixed some unexpected input (from the TxQ)
BigDumbDinosaur wrote:
Also, in foreground code in which you are waiting for a datum to become available (receive), or waiting for queue space to become available (transmit), you can gain a little interrupt performance by using the WAI instruction to stall the MPU instead of spinning in a loop. With the MPU WAIting in that fashion there will be no hardware interrupt latency when the DUART reports in—response time to an IRQ will not be more than one Ø2 cycle. Here's a code excerpt from my POC V1.2 BIOS that illustrates using WAI to block until TXQ space becomes available:

Code: Select all

;================================================================================
;
;putchcom: WRITE DATUM TO TIA-232 CHANNEL (common to all channels)
;
;	————————————————————————————————————————————————————————————————————————
;	Do not directly call this function, as the stack will become unbalanced.
;	Only use the PUTCHx functions, where x is the comm port ID.
;	————————————————————————————————————————————————————————————————————————
;
putchcom phy                   ;preserve...
         pha                   ;remaining registers
         phd
         pea #kerneldp
         pld                   ;set kernel direct page
         shortr
         xba                   ;protect datum
         txa                   ;channel index...
         asl                   ;becomes...
         tax                   ;channel offset
         lda tiaputtx,x        ;queue "put" index
         ina                   ;bump it &...
         and #m_tiaptr         ;mask to queue size
         ora tiaqpmsk,x        ;align to queue base addr
;
.main    cmp tiagettx,x        ;room in the queue?
         beq .qfull            ;no, wait
;
         xba                   ;swap queue pointer w/datum
         sta (tiaputtx,x)      ;put datum in queue
         xba                   ;new queue pointer
         sta tiaputtx,x        ;save it
         lda tiatstab,x        ;channel's TxD status mask
         trb tiatxst           ;transmitter running?
         bne .enabltx          ;no, enable it
;
.done    longr
         pld                   ;restore MPU status
         pla
         ply
         plx
         plp
         clc
         rts
;
;
;	block for TXQ space...
;
.qfull   wai                   ;wait for interrupt &...
         bra .main             ;try again
;
;
;	enable transmitter...
;
.enabltx lda #nxpcrtxe
         sta (tiacr,x)
         bra .done
;
This is something I am going totry in a newer spin of the ROM....
Post Reply