Page 2 of 3
Re: New modular design 65c816 based with Supermon816
Posted: Fri Feb 12, 2021 3:44 am
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.
Re: New modular design 65c816 based with Supermon816
Posted: Fri Feb 12, 2021 9:35 am
by xjmaas
Thank you for the feedback!
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?
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
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
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?
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....
Re: New modular design 65c816 based with Supermon816
Posted: Fri Feb 12, 2021 6:24 pm
by BigDumbDinosaur
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
Re: New modular design 65c816 based with Supermon816
Posted: Sat Feb 13, 2021 12:12 am
by BigDumbDinosaur
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 42 times
Re: New modular design 65c816 based with Supermon816
Posted: Tue Feb 16, 2021 9:42 am
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 routineCode: 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
Re: New modular design 65c816 based with Supermon816
Posted: Tue Feb 16, 2021 6:27 pm
by BigDumbDinosaur
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
Re: New modular design 65c816 based with Supermon816
Posted: Wed Feb 17, 2021 11:52 am
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 ^^^
Re: New modular design 65c816 based with Supermon816
Posted: Wed Feb 17, 2021 6:47 pm
by BigDumbDinosaur
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."
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.
Re: New modular design 65c816 based with Supermon816
Posted: Wed Feb 17, 2021 7:30 pm
by xjmaas
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."
I will change this comment
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)
Re: New modular design 65c816 based with Supermon816
Posted: Wed Feb 17, 2021 7:51 pm
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
Re: New modular design 65c816 based with Supermon816
Posted: Wed Feb 17, 2021 8:11 pm
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
Re: New modular design 65c816 based with Supermon816
Posted: Wed Feb 17, 2021 8:35 pm
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...
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

Re: New modular design 65c816 based with Supermon816
Posted: Fri Feb 19, 2021 12:39 pm
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?
Re: New modular design 65c816 based with Supermon816
Posted: Fri Feb 19, 2021 5:52 pm
by BigDumbDinosaur
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
;
Re: New modular design 65c816 based with Supermon816
Posted: Mon Feb 22, 2021 7:58 am
by xjmaas
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)
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....