6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 5:43 pm

All times are UTC




Post new topic Reply to topic  [ 32 posts ]  Go to page 1, 2, 3  Next
Author Message
PostPosted: Tue Jan 12, 2021 9:33 am 
Offline

Joined: Tue May 03, 2016 11:32 am
Posts: 41
Based on the RC2014 and my previous "design", Lilith, I created a new project: Adria, a modular computer. Adria is, currently, running Supermon816 as monitor, but with an Intel Hex uploader from ROM.

The first version/revision is complete through hole. I had JLCPCB develop the PCBs, easy, simple, 2-layer.
Currently I run Adria with a 4 MHz oscillator, which is divided by a 74HCT74 by 4, PHI2 is 1MHz.

My intention is to open source the whole project, so everyone might be able to play with it ;)
I'll try to get the page up on my website as soon as possible.

The card on the right is my test serial comms card based on a SY6551. (I am trying to get the Rx and Tx leds to blink correct).
Code:
Broken external image link
http://www.xjmaas.nl/wp-content/uploads/2021/01/IMG_5886-e1610443676197.jpg
Code:
Broken external image link
http://www.xjmaas.nl/wp-content/uploads/2021/01/IMG_5885-e1610443715809.jpg


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 12, 2021 9:50 am 
Offline

Joined: Tue May 03, 2016 11:32 am
Posts: 41
My main idea for Adria, was to have an easier way to "develop" additional hardware, like keyboard/video interface, storage interface, learn to use CPLD/FPGA (think MMU?)


Top
 Profile  
Reply with quote  
PostPosted: Tue Jan 12, 2021 9:06 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
Excellent! If there is anything the world needs right now it is more 65C816 designs, especially ones using Supermon 816. 8) Welcome to the club, so to speak.

P.S. In the next iteration, I recommend you use a 74AC74 in place of the 74HCT74 for clock generation. The HCT74's output rise and fall times don't quite meet WDC specs for the Ø2 input. As the AC74's rise and fall times are down near 1ns, I use series resistance between the flop's Q output and the rest of the circuit to dampen ringing. With Jeff's clock stretcher gadget installed it works out to 122Ω. Works great at 20 MHz. :)

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 13, 2021 11:13 am 
Offline

Joined: Tue May 03, 2016 11:32 am
Posts: 41
BigDumbDinosaur wrote:
P.S. In the next iteration, I recommend you use a 74AC74 in place of the 74HCT74 for clock generation. The HCT74's output rise and fall times don't quite meet WDC specs for the Ø2 input. As the AC74's rise and fall times are down near 1ns, I use series resistance between the flop's Q output and the rest of the circuit to dampen ringing. With Jeff's clock stretcher gadget installed it works out to 122Ω. Works great at 20 MHz. :)

This might be something I have to keep in mind in a new(er) revision ;)


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 03, 2021 10:03 am 
Offline

Joined: Tue May 03, 2016 11:32 am
Posts: 41
Currently I am trying to get a SC28L92 working with my board. I wired it up like mentioned in the PDFs from BDD, and tried to write a "userland" driver. I wanted to start simple by first writing the jiffy counter and respond to that IRQ signal.
But it seems the IRQ is not allowing me to get any input from my 6551 based serial/UART card, which doesn't use IRQ signalling.

I tried to write the driver based on information I found on the website for BDD's SBC (using a lot of his source code!) and reading through the PDFs, regarding the 26L9x and the 28L9x.

I have the current version of the source added as a ZIP file (hosted from my own site). I use cc65 (ca65)as my coding environment


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 03, 2021 3:03 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
xjmaas wrote:
Currently I am trying to get a SC28L92 working with my board...

You have two problems with your code, one which is fairly obvious and one which isn't. In your interrupt service routine's (ISR) front end, there is:

Code:
nx_irq:
        shortr                               ; 8 bit registers
        lda        IOBASE + dr_isr           ; Load IRQ register, did UART interrupt?
        beq        nx_irq_end                ; Nope
;
; vvv  DEBUG  vvv                       
        jsr        NEWLINE                   ; If we get here, UART has triggered
        jsr        DPYHEX
; ^^^  DEBUG  ^^^
;       
        pha                                  ; Save UART ISR
;
;-----------------------
;Contents of stack, which we
;(might) use in the routine
;-----------------------
@irq_isrx         = 1                        ; UART IRQ status
@irq_yreg         = @irq_isrx + s_byte       ; 16 bit .Y
@irq_xreg         = @irq_yreg  + s_word      ; 16 bit .X
@irq_areg         = @irq_xreg  + s_word      ; 16 bit .A
@irq_dpreg        = @irq_areg  + s_word      ; DP
@irq_dbreg        = @irq_dpreg + s_mpudpx    ; DB
; pushed by hardware
@irq_srreg        = @irq_dbreg + s_mpudbx    ; SR
@irq_pcreg        = @irq_srreg + s_mpusrx    ; PC
@irq_pbreg        = @irq_pcreg + s_mpupcx    ; PB

You are pushing the DUART's interrupt status after calling the NEWLINE and DPYHEX subs. Assuming those are Supermon 816 functions, you are clobbering .A in DPYHEX. Try pushing .A before the debugging calls and then execute lda irq_isrx,S afterward to restore .A.

The non-obvious problem is the debugging calls are (presumably) indirectly calling a foreground function (part of the serial I/O (SIO) driver?). However, you are in the middle of servicing an interrupt and IRQs were masked when the IRQ you are servicing was responded to by the MPU. That may prevent SIO from working.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 03, 2021 7:47 pm 
Offline

Joined: Tue May 03, 2016 11:32 am
Posts: 41
Grrrr, I now have a returning prompt, after running the nx_init routine. But when trying to measure the IRQ line, is seems to stay high all the time, as if the IRQ isn't triggering on the 28L92 (which was a brand new IC from Mouser)


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 03, 2021 8:58 pm 
Offline

Joined: Tue May 03, 2016 11:32 am
Posts: 41
I did just test if the 28L92 is actually "working" by storing a byte in register $0C (Misc register) and reloading from that register. This seems to work correctly


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 03, 2021 9:17 pm 
Offline

Joined: Tue May 03, 2016 11:32 am
Posts: 41
Maybe I have found the culprit...

"Adria" might have to enable the counter by reading IOBASE + dr_cnt_start (Start counter command)?!

I now have a 100Hz /IRQ signal and the counters are incrementing/decrementing...


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 03, 2021 9:43 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
xjmaas wrote:
Maybe I have found the culprit...

"Adria" might have to enable the counter by reading IOBASE + dr_cnt_start (Start counter command)?!

I now have a 100Hz /IRQ signal and the counters are incrementing/decrementing...

Yep! You do have to start the C/T. Once it's running in timer mode you should not issue another start, as it will immediately reload the timer registers with the prescalar value and thus cause a short timing cycle.

Incidentally, anything that reads the start and stop C/T registers will have the desired effect. For example, bit IOBASE+dr_cnt_start will work and will avoid clobbering a register. Just don't use a R-M-W instruction, since it will inadvertently affect the DUART in a way unrelated to the C/T.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 10, 2021 8:46 pm 
Offline

Joined: Tue May 03, 2016 11:32 am
Posts: 41
Got some more success with the driver (some reading here, some "stealing" there... crashes, having to rewrite IRQ handler in ROM to support separate emulation and native 65c816)

Currently I am stumbling upon an issue when sending large data sets.


Code:
000000r 1               ;===============================================================================
000000r 1               ;   A D R I A   - Philips/NXP 28L9x Driver skeleton
000000r 1               ;
000000r 1               ;    This source file is the base skeleton for the driver for the
000000r 1               ;   Philips/NXP 28L9x IC.
000000r 1               ;
000000r 1               ;   This driver is (largely) based on the driver by
000000r 1               ;   BDD (sbc.bcstechnology.net) and his documents "28l91 Driving" and
000000r 1               ;   "28L92 Interfacing".
000000r 1               ;   (Most of this driver is copied from/based on his work!)
000000r 1               ;
000000r 1               ;   Written for use with the CC65 assembler.
000000r 1               ;
000000r 1               ;   Version history:
000000r 1               ;      26 jan 2021 - Inital version
000000r 1               ;===============================================================================
000000r 1               ;   Linker directives
000000r 1               ;---------------------------------------
000000r 1                  .p816
000000r 1                  .listbytes   unlimited
000000r 1                  .smart       +
000000r 1               
000000r 1                  .org      $4000      ; Our driver will be loaded ...
004000  1                              ; ... at $4000 (16384)   
004000  1               ;
004000  1               ;---------------------------------------
004000  1               ;   Includes to sub-modules
004000  1               ;---------------------------------------
004000  1                  .include   "macro.asm"
004000  2               ;===============================================================================
004000  2               ;   A D R I A   - Philips/NXP 28L9x Macro file
004000  2               ;
004000  2               ;    This source file holds the global macro definitions to ease the
004000  2               ;   development of the drivre for the Philips/NXP 28L9x IC.
004000  2               ;
004000  2               ;   Version history:
004000  2               ;      26 jan 2021 - Inital version
004000  2               ;===============================================================================
004000  2               ;    Version information
004000  2               ;---------------------------------------
004000  2                  .macro   nx_9x_version
004000  2                  .byte   '0'         ; Major
004000  2                  .byte   '.'
004000  2                  .byte   '1'         ; Minor
004000  2                  .byte   '.'
004000  2                  .byte   '0'         ; Revision
004000  2                  .endmacro
004000  2               ;
004000  2               ;---------------------------------------
004000  2               ;   Register width selection
004000  2               ;---------------------------------------
004000  2                  .macro   longi         ; Set .X and .Y to 16-bit
004000  2                  rep   #%00010000
004000  2                  .i16
004000  2                  .endmacro
004000  2               
004000  2                  .macro   shorti         ; Set .X and .Y to 8-bit
004000  2                  sep   #%00010000
004000  2                  .i8
004000  2                  .endmacro
004000  2               
004000  2                  .macro   longa         ; Set .A to 16-bit
004000  2                  rep   #%00100000
004000  2                  .a16
004000  2                  .endmacro
004000  2               
004000  2                  .macro   shorta         ; Set .A to 8-bit
004000  2                  sep   #%00100000
004000  2                  .a8
004000  2                  .endmacro
004000  2               
004000  2                  .macro   longr         ; Set all registers to 16-bit
004000  2                  rep   #%00110000      ; Set 16-bit .A, .X and .Y
004000  2                  .a16
004000  2                  .i16
004000  2                  .endmacro
004000  2               
004000  2                  .macro   shortr         ; Set all registers to 8-bit
004000  2                  sep   #%00110000      ; Set 8-bit .A, .X and .Y
004000  2                  .a8
004000  2                  .i8
004000  2                  .endmacro
004000  2               ;
004000  2               
004000  1                  .include   "global.asm"
004000  2               ;===============================================================================
004000  2               ;   A D R I A   - Philips/NXP 28L9x Global definitions file
004000  2               ;
004000  2               ;    This source file holds the global definitions for the drivre for the
004000  2               ;   Philips/NXP 28L9x IC.
004000  2               ;
004000  2               ;   Version history:
004000  2               ;      26 jan 2021 - Inital version
004000  2               ;===============================================================================
004000  2               ; GENERIC
004000  2               ;=======================================
004000  2               ; Size data types
004000  2               ;---------------------------------------
004000  2               s_bi_bit   = 1         ;  1 bit
004000  2               s_bi_nibble   = 4         ;  4 bit, nibble (or nybble)
004000  2               s_bi_nybble   = s_bi_nibble
004000  2               s_bi_byte   = 8         ;  8 bit, 1 byte
004000  2               ;
004000  2               s_byte      = 1         ;  8 bit, 1 byte
004000  2               s_word      = 2         ; 16 bit, 2 bytes
004000  2               s_xword      = 3         ; 24 bit, 3 bytes
004000  2               s_dword      = 4         ; 32 bit, 4 bytes
004000  2               ;
004000  2               s_ptr      = s_word      ; Pointer   , 16 bit, 2 bytes
004000  2               s_dptr      = s_word * 2      ; Double pointer, 32 bit, 4 bytes
004000  2               s_rampage   = $0100         ; 65xx size of RAM page (256 bytes)
004000  2               s_bank      = $ffff         ; 65816 size of RAM bank (65536 bytes)
004000  2               ;
004000  2               s_mpudbx   = s_byte      ; Size of Data Bank register
004000  2               s_mpudpx   = s_word      ; Size of Direct Page register
004000  2               s_mpupbx   = s_byte      ; Size of Program Bank register
004000  2               s_mpupcx   = s_word      ; Size of Program Counter register
004000  2               s_mpuspx   = s_word      ; Size of Stack Pointer register
004000  2               s_mpusrx   = s_byte      ; Size of Processor Status register
004000  2               ;
004000  2               ;---------------------------------------
004000  2               ; Flags
004000  2               ;---------------------------------------
004000  2               ;    Status Register
004000  2               ;         +----------> 1 = result = negative
004000  2               ;         |+---------> 1 = sign overflow
004000  2               ;         ||           1 = 8 bit .A & memory
004000  2               ;         ||+--------> 0 = 16 bit .A & memory
004000  2               ;         |||          1 = 8 bit index
004000  2               ;         |||+-------> 0 = 16 bit index
004000  2               ;         ||||         1 = decimal arithmetic mode
004000  2               ;         ||||+------> 0 = binary arithmetic mode
004000  2               ;         |||||+-----> 1 = IRQ disabled
004000  2               ;         ||||||+----> 1 = result = zero
004000  2               ;         |||||||+---> 1 = carry set/generated
004000  2               ;         ||||||||
004000  2               ;         NVmxDIZC
004000  2               ;---------------
004000  2               sr_carry   = %0000001      ; C => carry
004000  2               sr_zero      = sr_carry    << 1   ; Z => zero
004000  2               sr_irq      = sr_zero    << 1   ; I => IRQ
004000  2               sr_bdm      = sr_irq    << 1   ; D => decimal mode
004000  2               sr_ixw      = sr_bdm   << 1   ; x => index register width
004000  2               sr_amw      = sr_ixw   << 1   ; m => memory and .A width
004000  2               sr_ovl      = sr_amw   << 1   ; V => overflow
004000  2               sr_neg      = sr_ovl   << 1   ; N => negative
004000  2               ;---------------
004000  2               ;    Status Register - Inverted
004000  2               ;---------------
004000  2               sr_carry_i   = sr_carry ^ %11111111   ; C
004000  2               sr_zero_i   = sr_zero  ^ %11111111   ; Z
004000  2               sr_irq_i   = sr_irq   ^ %11111111   ; I
004000  2               sr_bdm_i   = sr_bdm   ^ %11111111   ; D
004000  2               sr_ixw_i   = sr_ixw   ^ %11111111   ; x
004000  2               sr_amw_i   = sr_amw   ^ %11111111   ; m
004000  2               sr_ovl_i   = sr_ovl   ^ %11111111   ; V
004000  2               sr_neg_i   = sr_neg   ^ %11111111   ; N
004000  2               ;
004000  2               ;---------------------------------------
004000  2               ; Constants
004000  2               ;---------------------------------------
004000  2               BELL      = $07         ; <Bell>
004000  2               BS      = $08         ; <Backspace>
004000  2               HTAB      = $09         ; <Tab>
004000  2               LF      = $0A         ; <LF>
004000  2               CR      = $0D         ; <CR>
004000  2               SPACE      = $20         ; <Space>
004000  2               DEL      = $7F         ; <Del>
004000  2               ;
004000  2               ;---------------------------------------
004000  2               ; Pointers/addresses
004000  2               ;---------------------------------------
004000  2               ;   SUPERMON816
004000  2               ;---------------
004000  2               DPYHEX      = $DFAD         ; Display contents of .A as byte
004000  2               NEWLINE      = $DFC4         ; Go to new line
004000  2               ;---------------
004000  2               ;   ROM
004000  2               ;---------------
004000  2               VECTOR_INT   = $02D8         ; /IRQ jump vector
004000  2               CHKSUM_INT   = $02DA         ; /IRQ jump vector checksum
004000  2               CHAR_OUT   = $FD0C         ; Current Character Out jump routine
004000  2               ;
004000  2               ;=======================================
004000  2               ;    DRIVER
004000  2               ;=======================================
004000  2               ; Size data types
004000  2               ;---------------------------------------
004000  2               s_uptime   = s_dword      ; Uptime ticker   , 32 bit, 4 bytes
004000  2               ;
004000  2               s_e32_buf   = s_rampage / 2      ; Size of a UART I/O buffer
004000  2               s_e32_space   = s_e32_buf * n_e32_buf   ; Total space reserved for UART I/O
004000  2                              ; buffers
004000  2               ;
004000  2               ;---------------------------------------
004000  2               ; Flags
004000  2               ;---------------------------------------
004000  2               ;   Channel TxD status
004000  2               ;    Only A and B are used, rest is
004000  2               ;   already defined for future use
004000  2               e32_tx_sta   = %00000001      ; Channel A TxD status
004000  2               e32_tx_stb   = e32_tx_sta   << 1   ; Channel B TxD status
004000  2               e32_tx_stc   = e32_tx_stb   << 1   ; Channel C TxD status
004000  2               e32_tx_std   = e32_tx_stc   << 1   ; Channel D TxD status
004000  2               e32_tx_ste   = e32_tx_std   << 1   ; Channel E TxD status
004000  2               e32_tx_stf   = e32_tx_ste   << 1   ; Channel F TxD status
004000  2               e32_tx_stg   = e32_tx_stf   << 1   ; Channel G TxD status
004000  2               e32_tx_sth   = e32_tx_stg   << 1   ; Channel H TxD status
004000  2               ;
004000  2               buf_idx_mask   = s_e32_buf ^ %11111111   ; Buffer index wrap mask
004000  2               ;
004000  2               ; 28L9x driver status flags
004000  2               nx_driver_init   = %10000000      ; Driver initialization status
004000  2               nx_txa_dis   = %01000000      ; TxD channel A flag
004000  2               nx_txb_dis   = %00100000      ; TxD channel B flag
004000  2               ;
004000  2               ;   SR masks
004000  2               msk_sr_rx_rdy   = %00000001      ; RHR not empty mask
004000  2               msk_sr_rx_full   = %00000010      ; RHR full empty
004000  2               msk_sr_tx_rdy   = %00000100      ; THR not full mask
004000  2               msk_sr_tx_empty   = %00001000      ; THR empty mask
004000  2               ;
004000  2               ;   IRQ masks
004000  2               ;---------------
004000  2               msk_irq_txa   = %00000001      ; Channel A TxRDY IRQ mask
004000  2               msk_irq_rxa   = %00000010      ; Channel A RxRDY IRQ mask
004000  2               msk_irq_ct   = %00001000      ; Counter Ready Mask
004000  2               msk_irq_txb   = %00010000      ; Channel B TxRDY IRQ mask
004000  2               msk_irq_rxb   = %00100000      ; Channel B RxRDY IRQ mask
004000  2               ;
004000  2               ;---------------------------------------
004000  2               ; Constants
004000  2               ;---------------------------------------
004000  2               n_chan_9x   = 2         ; Number of channels
004000  2               n_reg_9x   = 8         ; Number of registers per channel
004000  2               n_tot_reg_9x   = n_chan_9x * n_reg_9x   ; Total number of registers
004000  2               ;
004000  2               ;nx_q_size   = s_rampage / 2      ; Size of a ring buffer (127)
004000  2               nx_q_size   = s_rampage      ; Size of a ring buffer (255)
004000  2               nx_q_base   = $2000         ; For now we define our queues at $2000
004000  2               nx_rx_qa   = nx_q_base      ; RxD queue channel A
004000  2               nx_tx_qa   = nx_rx_qa + nx_q_size   ; TxD queue channel A
004000  2               nx_rx_qb   = nx_tx_qa + nx_q_size   ; RxD queue channel B
004000  2               nx_tx_qb   = nx_rx_qb + nx_q_size   ; TxD queue channel B
004000  2               ;
004000  2               n_e32_buf   = 4         ; # of UART I/O buffers
004000  2               ;
004000  2               x1_freq      = 3686400      ; Clock freq of X1 in Hz
004000  2               nx_ct_scale   = x1_freq / 2      ; C/T scaled clock
004000  2               hz      = 100         ; Frequency of C/T IRQs (in Hz)
004000  2               ;
004000  2               ;---------------------------------------
004000  2               ; Pointers/addresses
004000  2               ;---------------------------------------
004000  2               ;    Zeropage / Direct Page
004000  2               ;---------------
004000  2               nx_zeropage   = $20         ; We use ZP from $20
004000  2               nx_jiffycnt   = nx_zeropage      ; Jiffy counter
004000  2               ;---------------
004000  2               ;   Uptime is little endian!
004000  2               ;---------------
004000  2               nx_uptimecnt   = nx_jiffycnt  + s_byte   ; 32 bit uptime counter
004000  2               ;
004000  2               ;   RxD and TxD GET and PUT indexes channel A
004000  2               nx_rx_get_a   = nx_uptimecnt + s_dword;
004000  2               nx_tx_get_a   = nx_rx_get_a  + s_byte   ;
004000  2               nx_rx_put_a   = nx_tx_get_a  + s_byte   ;
004000  2               nx_tx_put_a   = nx_rx_put_a  + s_byte   ;
004000  2               ;
004000  2               ;   RxD and TxD GET and PUT indexes channel B
004000  2               nx_rx_get_b   = nx_tx_put_a  + s_byte   ;
004000  2               nx_tx_get_b   = nx_rx_get_b  + s_byte   ;
004000  2               nx_rx_put_b   = nx_tx_get_b  + s_byte   ;
004000  2               nx_tx_put_b   = nx_rx_put_b  + s_byte   ;
004000  2               ;
004000  2               nx_tx_status   = nx_tx_put_b + s_byte   ; Driver TxD status register
004000  2               ;
004000  2               rom_irq      = nx_tx_status + s_byte   ; Store original IRQ jump vector!
004000  2               ;---------------
004000  2               ;    I/O
004000  2               ;---------------
004000  2               IOBASE      = $C400         ; NXP 28L92 is based in slot #4
004000  2               ;
004000  2               ;---------------------------------------
004000  2               ; Data Registers
004000  2               ;---------------------------------------
004000  2               ;   Offsets to IO_BASE
004000  2               ;---------------
004000  2               dr_mra      = %0000         ; Mode Register A
004000  2               dr_sra      = %0001         ; Status Register a
004000  2               dr_rxfifoa   = %0011         ; Rx Holding Register A
004000  2               dr_ipcr      = %0100         ; Input Port Change Register
004000  2               dr_isr      = %0101         ; Interrupt Status Register
004000  2               dr_ctu      = %0110         ; Counter/Timer (MSB)
004000  2               dr_ctl      = %0111         ; Counter/Timer (LSB)
004000  2               dr_mrb      = %1000         ; Mode Register B
004000  2               dr_srb      = %1001         ; Status Register B
004000  2               dr_rxfifob   = %1011         ; Rx Holding Register B
004000  2               dr_misc      = %1100         ; Miscellaneous Register (Intel mode)
004000  2               dr_ipr      = %1101         ; Input Port Register
004000  2               dr_cnt_start   = %1110         ; Start counter command
004000  2               dr_cnt_stop   = %1111         ; Stop counter command
004000  2               ; During write
004000  2               ;dr_mra   = %0000            ; Mode Register A (Same when Reading)
004000  2               dr_csra      = %0001         ; Clock Select Register A
004000  2               dr_cra      = %0010         ; Command Register A
004000  2               dr_txfifoa   = %0011         ; Tx Holding Register A
004000  2               dr_acr      = %0100         ; Auxiliary Control Register
004000  2               dr_imr      = %0101         ; Interrupt Mask Register
004000  2               dr_ctpu      = %0110         ; Counter/Timer Upper Preset Reg (MSB)
004000  2               dr_ctpl      = %0111         ; Counter/Timer Lower Preset Reg (LSB)
004000  2               ;dr_mrb      = %1000         ; Mode Register B (Same when Reading)
004000  2               dr_csrb      = %1001         ; Clock Select Register B
004000  2               dr_crb      = %1010         ; Command Register B
004000  2               dr_txfifob   = %1011         ; Tx Holding Register B
004000  2               ;dr_misc   = %1100         ; Miscellaneous Register (Intel mode)
004000  2               dr_opcr      = %1101         ; Output Port Configuration Register
004000  2               dr_sopr      = %1110         ; Set Output Port Bits Command
004000  2               dr_ropr      = %1111         ; Reset Output Port Bits Command
004000  2               ;---------------------------------------
004000  2               ; 29L9x Registers (explained)
004000  2               ;---------------------------------------
004000  2               ;   MISC - Miscellaneous Register (Intel mode)
004000  2               ;
004000  2               ; We only explain the possible flags
004000  2               ;
004000  2               nx_misc_def   = %00000000
004000  2               ;         xxxxxxxx
004000  2               ;         ||||||||
004000  2               ;         |||+++++---> z: Unused
004000  2               ;         |||
004000  2               ;         ||+--------> 1: Disable transmitter channel B
004000  2               ;         |+---------> 1: Disable transmitter channel A
004000  2               ;         +----------> 1: Driver initialized
004000  2               ;---------------
004000  2               ;    ACR - Auxiliary Control Register
004000  2               ;---------------
004000  2               nx_acr_def   = %01100000
004000  2               ;         xxxxxxxx
004000  2               ;         ||||||||
004000  2               ;         |||||||+---> 1: enable IP0 IRQ
004000  2               ;         ||||||+----> 1: enable IP1 IRQ
004000  2               ;         |||||+-----> 1: enable IP2 IRQ
004000  2               ;         ||||+------> 1: enable IP3 IRQ
004000  2               ;         |+++-------> C/T setup:
004000  2               ;         |
004000  2               ;         |            654  Mode     Source
004000  2               ;         |            -------------------------------
004000  2               ;         |            000  counter  IP2
004000  2               ;         |            001  counter  TxD Ch 1 1X clock
004000  2               ;         |            010  counter  TxD Ch 2 1X clock
004000  2               ;         |            011  counter  Xtal/16
004000  2               ;         |            100  timer    IP2
004000  2               ;         |            101  timer    IP2/16
004000  2               ;         |            110  timer    Xtal
004000  2               ;         |            111  timer    Xtal/16
004000  2               ;         |            -------------------------------
004000  2               ;         |
004000  2               ;         +----------> 0: select BRG set #1 (38.4k max)
004000  2               ;                      1: select BRG set #2 (19.2k max)
004000  2               ;
004000  2               ;---------------
004000  2               ;    CR - Command Register
004000  2               ;---------------
004000  2               nx_cr_rx_ena   = %00000001      ; Enable receiver
004000  2               nx_cr_rx_dis   = %00000010      ; Disable receiver
004000  2               ;
004000  2               nx_cr_tx_ena   = %00000100      ; Enable transmitter
004000  2               nx_cr_tx_dis   = %00001000      ; Disable transmitter
004000  2               ;
004000  2               nx_cr_mr1   = %00010000      ; Select MR1
004000  2               ;
004000  2               nx_cr_rx_res   = %00100000      ; Reset receiver
004000  2               nx_cr_tx_res   = %00110000      ; Reset transmitter
004000  2               nx_cr_err_res   = %01000000      ; Reset error status
004000  2               nx_cr_bir_res   = %01010000      ; Reset Received Break Change IRQ
004000  2               ;
004000  2               nx_cr_brk_sta   = %01100000      ; Start break
004000  2               nx_cr_brk_stp   = %01110000      ; Stop break
004000  2               ;
004000  2               nx_cr_rts_ass   = %10000000      ; Assert RTS
004000  2               nx_cr_rts_dea   = %10010000      ; Deassert RTS
004000  2               ;
004000  2               nx_cr_tmr_mod   = %10100000      ; Select C/T timer mode
004000  2               ;
004000  2               nx_cr_mr0   = %10110000      ; Select MR0
004000  2               ;
004000  2               nx_cr_cnt_mod   = %11000000      ; Select C/T counter mode
004000  2               ;
004000  2               nx_cr_pwr_dwn   = %11100000      ; Power down mode   (Port A only)
004000  2               nx_cr_pwr_up   = %11110000      ; Normal power mode   (Port A only)
004000  2               ;
004000  2               ;   Combined CR commands
004000  2               nx_cr_rxtx_ena   = nx_cr_rx_ena | nx_cr_tx_ena
004000  2               nx_cr_rxtx_dis   = nx_cr_rx_dis | nx_cr_tx_dis
004000  2               ;
004000  2               ;---------------
004000  2               ;    CSR - Clock Select Register
004000  2               ;---------------
004000  2               nx_csr      = %11001100      ; RxD and TxD at 38k4 baud
004000  2                              ; MR[0] = 0 & ACR[7] = 0
004000  2               ;---------------
004000  2               ;    CT - Counter / Timer
004000  2               ;---------------
004000  2               nx_cnt_lo   = <(nx_ct_scale/hz)   ; Underflows/sec LSB
004000  2               nx_cnt_hi   = >(nx_ct_scale/hz)   ; Underflows/sec MSB
004000  2               ;
004000  2               ;---------------
004000  2               ;    IMR - Interrupt Mask Register
004000  2               ;---------------
004000  2                              ; Enable channel A RxD and TxD IRQs
004000  2               nx_irq_a   = msk_irq_txa | msk_irq_rxa
004000  2                              ; Enable channel B RxD and TxD IRQs
004000  2               nx_irq_b   = msk_irq_txb | msk_irq_rxb
004000  2                              ; Set IRQ Sources (Port A, B and C/T)
004000  2               nx_irq_msk   = nx_irq_a | nx_irq_b | msk_irq_ct
004000  2               ;
004000  2               ;---------------
004000  2               ;    MR0 - Mode 0 Register
004000  2               ;---------------
004000  2               nx_mr0      = %11001000
004000  2               ;         ||||||||
004000  2               ;         |||||+++----> Baud rate: Normal mode
004000  2               ;         ||||+-------> 16-deep FIFO
004000  2               ;         ||++--------> TxD interrupts only when FIFO is empty
004000  2               ;         |+----------> RxD interrupts only when FIFO is full
004000  2               ;         |             (also see MR1[6])
004000  2               ;         +-----------> Enable RxD watchdog timer
004000  2               ;
004000  2               ;---------------
004000  2               ;    MR1 - Mode 1 Register
004000  2               ;---------------
004000  2               nx_mr1      = %11010011
004000  2               ;         ||||||||
004000  2               ;         ||||||++----> 8 bit character size
004000  2               ;         |||||+------> Parity type (ignored)
004000  2               ;         |||++-------> No parity generated or checked
004000  2               ;         ||+---------> Character error mode
004000  2               ;         |+----------> RxD interrupts only when FIFO is full
004000  2               ;         |       (See also MR0[6]
004000  2               ;         +-----------> RxD controls RTS
004000  2               ;
004000  2               ;---------------
004000  2               ;    MR2 - Mode 2 Register
004000  2               ;---------------
004000  2               nx_mr2      = %00010111      ; Normal mode, auto RTS
004000  2               ;         ||||||||
004000  2               ;         ||||++++---> stop bit length
004000  2               ;         ||||
004000  2               ;         |||+-------> TxD CTS mode:      0: off
004000  2               ;         |||                             1: on
004000  2               ;         ||+--------> TxD RTS mode:      0: off
004000  2               ;         ||                              1: on
004000  2               ;         ++---------> channel mode:    00: normal
004000  2               ;                                    01: auto echo
004000  2               ;                                    10: local loop
004000  2               ;                                    11: remote loop
004000  2               ;
004000  2               ;---------------
004000  2               ;    OPCR - Output Port Configuration Register
004000  2               ;---------------
004000  2               nx_opcr_def   = %11110000      ; OP4-7 as IRQ outputs
004000  2               
004000  2               
004000  2               
004000  1                  .include   "frontend.asm"
004000  2               ;===============================================================================
004000  2               ;   A D R I A   - Philips/NXP 28L9x Front-end routine(s)
004000  2               ;
004000  2               ;    This source file holds the front-end routine(s) for the
004000  2               ;   Philips/NXP 28L9x IC.
004000  2               ;
004000  2               ;   Version history:
004000  2               ;      26 jan 2021 - Inital version
004000  2               ;===============================================================================
004000  2               ; Process Receive Request
004000  2               ;
004000  2               ; Call the subroutine and the routine will try to "get" a datum from the
004000  2               ; corresponding RxQ. If this succeeds, the routine will return:
004000  2               ;   .A   - valid datum
004000  2               ;   carry   - clear
004000  2               ;
004000  2               ; If no datum is present in the RxQ, the routine will return:
004000  2               ;   .A   - unchanged
004000  2               ;   carry   - set
004000  2               ;
004000  2               ; NOTE: Carry will also be returned set, if the driver hasn't been initialized,
004000  2               ;   yet...
004000  2               ;-------------------------------------------------------------------------------
004000  2               ; nx_sioget_a - Process datum from channel A RxQ
004000  2               ;-----------------------
004000  2               nx_sioget_a:
004000  2  E2 30           shortr            ; Make sure we are in 8-bit registers
004002  2  38              sec            ; Default: assume error
004003  2  2C 0C C4        bit   IOBASE + dr_misc   ; Read bit 7 of dr_misc, if set, driver
004006  2                              ; has been initialized
004006  2  10 0E           bpl   @done         ; No, error
004008  2               ;
004008  2  DA              phx            ; Save .X
004009  2  A6 25           ldx   nx_rx_get_a      ; RxD "get" index
00400B  2  E4 27           cpx   nx_rx_put_a      ; Compare with RxD "put" index
00400D  2  F0 06           beq   @no_datum      ; No datum available
00400F  2               ;
00400F  2  BD 00 20        lda   nx_rx_qa, X      ; Get datum from queue
004012  2  E6 25           inc   nx_rx_get_a      ; Increment "get" index
004014  2  18              clc            ; Clear error (carry)
004015  2               ;
004015  2               @no_datum:
004015  2  FA              plx            ; Restore .X
004016  2               ;
004016  2               @done:
004016  2  60              rts
004017  2               ;
004017  2               ;-----------------------
004017  2               ; nx_sioget_b - Process datum from channel B RxQ
004017  2               ;-----------------------
004017  2               nx_sioget_b:
004017  2  E2 30           shortr            ; Make sure we are in 8-bit registers
004019  2  38              sec            ; Default, assume error
00401A  2  2C 0C C4        bit   IOBASE + dr_misc   ; Read bit 7 of dr_misc, if set, driver
00401D  2                              ; has been initialized
00401D  2  10 0E           bpl   @done         ; No, error
00401F  2               ;
00401F  2  DA              phx            ; Save .X
004020  2  A6 29           ldx   nx_rx_get_b      ; RxD "get" index
004022  2  E4 2B           cpx   nx_rx_put_b      ; Compare with RxD "put" index
004024  2  F0 06           beq   @no_datum      ; No datum available
004026  2               ;
004026  2  BD 00 22        lda   nx_rx_qb, X      ; Get datum from queue
004029  2  E6 29           inc   nx_rx_get_b      ; Increment "get" index
00402B  2  18              clc            ; Clear error (carry)
00402C  2               ;
00402C  2               @no_datum:
00402C  2  FA              plx            ; Restore .X
00402D  2               ;
00402D  2               @done:
00402D  2  60              rts
00402E  2               ;
00402E  2               ;-------------------------------------------------------------------------------
00402E  2               ; Process Transmit Request
00402E  2               ;
00402E  2               ; Call the subroutine and the routine will try to "put" a datum into the
00402E  2               ; corresponding TxQ. If this succeeds, the routine will return:
00402E  2               ;   carry   - clear
00402E  2               ;
00402E  2               ; NOTE: Carry will be set, if the driver hasn't been initialized,
00402E  2               ;   yet...
00402E  2               ;-------------------------------------------------------------------------------
00402E  2               ; nx_sioput_a - Process datum for channel A TxQ
00402E  2               ;-----------------------
00402E  2               nx_sioput_a:
00402E  2  E2 30           shortr            ; 8 bit registers
004030  2  38              sec            ; Default, assume error
004031  2  2C 0C C4        bit   IOBASE + dr_misc   ; Read bit 7 of dr_misc, if set, driver
004034  2                              ; has been initialized
004034  2  10 1E           bpl   @done         ; No, error!
004036  2               ;
004036  2  48              pha            ; Preserve .A
004037  2  DA              phx            ; Preserve .X
004038  2  A6 28           ldx   nx_tx_put_a      ; TxQ "put" index
00403A  2  E8              inx
00403B  2               ;
00403B  2               @full:
00403B  2  E4 26           cpx   nx_tx_get_a      ; TxQ "get" index
00403D  2  F0 FC           beq   @full         ; TxQ is full, block...
00403F  2               ;
00403F  2  CA              dex            ; Realign "put" index and ...
004040  2  9D 00 21        sta   nx_tx_qa, X      ; ... put datum into TxQ
004043  2  E6 28           inc   nx_tx_put_a      ; Bump "put" index
004045  2               ;
004045  2               ;---------------
004045  2               ;   Manage transmitter
004045  2               ;---------------
004045  2  A9 40           lda   #nx_txa_dis      ; Transmitter disabled flag
004047  2  1C 0C C4        trb   IOBASE + dr_misc   ; is transmitter disabled?
00404A  2  F0 05           beq   @cleanup      ; No
00404C  2               ;
00404C  2  A9 04           lda   #nx_cr_tx_ena      ; Yes, enable transmitter
00404E  2  8D 02 C4        sta   IOBASE + dr_cra
004051  2               ;
004051  2               @cleanup:
004051  2  FA              plx
004052  2  68              pla
004053  2  18              clc
004054  2               ;
004054  2               @done:
004054  2  60              rts
004055  2               ;
004055  2               ;-----------------------
004055  2               ; nx_sioput_b - Process datum from channel B TxQ
004055  2               ;-----------------------
004055  2               nx_sioput_b:
004055  2  E2 30           shortr            ; 8 bit registers
004057  2  38              sec            ; Default, assume error
004058  2  2C 0C C4        bit   IOBASE + dr_misc   ; Read bit 7 of dr_misc, if set, driver
00405B  2                              ; has been initialized
00405B  2  10 1E           bpl   @done         ; No, error!
00405D  2               ;
00405D  2  48              pha            ; Preserve .A
00405E  2  DA              phx            ; Preserve .X
00405F  2  A6 2C           ldx   nx_tx_put_b      ; TxQ "put" index
004061  2  E8              inx
004062  2               ;
004062  2               @full:
004062  2  E4 2A           cpx   nx_tx_get_b      ; TxQ "get" index
004064  2  F0 FC           beq   @full         ; TxQ is full, block...
004066  2               ;
004066  2  CA              dex            ; Realign "put" index and ...
004067  2  9D 00 21        sta   nx_tx_qa, X      ; ... put datum into TxQ
00406A  2  E6 2C           inc   nx_tx_put_b      ; Bump "put" index
00406C  2               ;
00406C  2               ;---------------
00406C  2               ;   Manage transmitter
00406C  2               ;---------------
00406C  2  A9 20           lda   #nx_txb_dis      ; Transmitter disabled flag
00406E  2  1C 0C C4        trb   IOBASE + dr_misc   ; is transmitter disabled?
004071  2  F0 05           beq   @cleanup      ; No
004073  2               ;
004073  2  A9 04           lda   #nx_cr_tx_ena      ; Yes, enable transmitter
004075  2  8D 0A C4        sta   IOBASE + dr_crb
004078  2               ;
004078  2               @cleanup:
004078  2  FA              plx
004079  2  68              pla
00407A  2  18              clc
00407B  2               ;
00407B  2               @done:
00407B  2  60              rts
00407C  2               ;
00407C  2               ;-------------------------------------------------------------------------------
00407C  2               ; UART Channel B Control
00407C  2               ;
00407C  2               ; Enable/disable channel based on carry value. Routine is based (copied ;)) from
00407C  2               ; BDD's SBC POCv1 ROM
00407C  2               ;
00407C  2               ; carry = 1   => Enable channel B
00407C  2               ; carry = 0   => Disable channel B
00407C  2               ;-------------------------------------------------------------------------------
00407C  2               nx_chan_b_ctl:
00407C  2  E2 20           shorta
00407E  2  90 04           bcc   nx_dis_chanb      ; If carry is cleared, disable channel B
004080  2               ;
004080  2               nx_ena_chanb:
004080  2  A9 85           lda   #(nx_cr_rxtx_ena | nx_cr_rts_ass)
004082  2  80 02           bra   nx_chanctl      ; Write to DUART command register
004084  2               ;
004084  2               nx_dis_chanb:
004084  2  A9 9A           lda   #(nx_cr_rxtx_dis | nx_cr_rts_dea)
004086  2               ;
004086  2               nx_chanctl:
004086  2  8D 0A C4        sta   IOBASE + dr_crb      ; Save to Command Register channel B
004089  2  CB              wai            ; We have to wait two /IRQs?
00408A  2  CB              wai
00408B  2  60              rts
00408C  2               
00408C  1                  .include   "interrupt.asm"
00408C  2               ;===============================================================================
00408C  2               ;   A D R I A   - Philips/NXP 28L9x Interrupt handler(s)
00408C  2               ;
00408C  2               ;    This source file holds the interrupt handler(s) (back-end of driver)
00408C  2               ;   for the Philips/NXP 28L9x IC.
00408C  2               ;
00408C  2               ;   Version history:
00408C  2               ;      26 jan 2021 - Inital version
00408C  2               ;===============================================================================
00408C  2               ; nx_irq - Hardware Interrupt Request Service routine
00408C  2               ;-------------------------------------------------------------------------------
00408C  2               nx_irq:
00408C  2  E2 30           shortr            ; 8 bit registers
00408E  2               ;
00408E  2  AD 05 C4        lda   IOBASE + dr_isr      ; Load IRQ register, did UART interrupt?
004091  2               ;
004091  2               ;
004091  2               ; Seems when adding another channel, the branch is taken too long ;) had to
004091  2               ; solve it somehow
004091  2               ;   beq   nx_irq_end      ; Nope
004091  2  D0 03           bne   @save_ISR      ; Very short branch
004093  2  4C FB 40        jmp   nx_irq_end      ; And we use a jump
004096  2               ;
004096  2               @save_ISR:
004096  2  E2 20           shorta
004098  2  48              pha            ; As per tip from BDD
004099  2                              ; (see forum.6502.org) I now push .A
004099  2                              ; to the stack before!
004099  2               ;
004099  2               ;-----------------------
004099  2               ;   Contents of stack, which we
004099  2               ;   (might) use in the routine
004099  2               ;-----------------------
004099  2               irq_isrx   = 1         ; UART IRQ status
004099  2               irq_yreg   = irq_isrx + s_byte         ; 16 bit .Y
004099  2               irq_xreg   = irq_yreg  + s_word   ; 16 bit .X
004099  2               irq_areg   = irq_xreg  + s_word   ; 16 bit .A
004099  2               irq_dpreg   = irq_areg  + s_word   ; DP
004099  2               irq_dbreg   = irq_dpreg + s_mpudpx   ; DBR
004099  2               ; pushed by hardware
004099  2               irq_srreg   = irq_dbreg + s_mpudbx   ; SR
004099  2               irq_pcreg   = irq_srreg + s_mpusrx   ; PC
004099  2               irq_pbreg   = irq_pcreg + s_mpupcx   ; PBR
004099  2               ;
004099  2               ;-----------------------
004099  2               ; Test for C/T IRQ
004099  2               ;-----------------------
004099  2               test_ct:
004099  2               ;
004099  2  89 08           bit   #msk_irq_ct      ; Did C/T interrupt?
00409B  2  F0 16           beq   test_rhr_a      ; Nope, skip this section
00409D  2               ;
00409D  2               ;-----------------------
00409D  2               ; Process C/T IRQ
00409D  2               ;-----------------------
00409D  2               @handle_ct:
00409D  2  AE 0F C4        ldx   IOBASE + dr_cnt_stop   ; Reset C/T IRQ
0040A0  2  A6 20           ldx   nx_jiffycnt      ; Get jiffy counter
0040A2  2  CA              dex            ; Decrement by one
0040A3  2  D0 0C           bne   @upd_jiffy      ; Not time, yet, to update uptime
0040A5  2               ;
0040A5  2  C2 20           longa            ; 16 bit .A
0040A7  2  E6 21           inc   nx_uptimecnt      ; increment uptime LSW
0040A9  2  D0 02           bne   @reset_jiffy      ; Done with uptime
0040AB  2               ;
0040AB  2  E6 23           inc   nx_uptimecnt + s_word   ; Increment uptime MSW
0040AD  2               ;
0040AD  2               @reset_jiffy:
0040AD  2  E2 30           shortr            ; 8 bit .A
0040AF  2  A2 64           ldx   #hz         ; Reset jiffy count
0040B1  2               ;
0040B1  2               @upd_jiffy:
0040B1  2  86 20           stx   nx_jiffycnt      ; Set new jiffy count value
0040B3  2               ;
0040B3  2               ;-----------------------
0040B3  2               ; Test for channel A RHR IRQ
0040B3  2               ;-----------------------
0040B3  2               test_rhr_a:
0040B3  2  E2 30           shortr
0040B5  2  A3 01           lda   irq_isrx, S      ; Get original ISR from stack
0040B7  2  89 02           bit   #msk_irq_rxa      ; Did receiver A request?
0040B9  2  F0 13           beq   test_rhr_b      ; Nope, check channel B
0040BB  2               ;-----------------------
0040BB  2               ; Process channel A RHR IRQ
0040BB  2               ;
0040BB  2               ; Enter loop to service RHR. Loop will not break until RHR is empty
0040BB  2               ;-----------------------
0040BB  2               @handle_rhr_a:
0040BB  2               ; Taken from pocrom v1 source
0040BB  2  AC 03 C4        ldy   IOBASE + dr_rxfifoa   ; Read RHR
0040BE  2  A6 27           ldx   nx_rx_put_a      ; Read buffer "put" index
0040C0  2  8A              txa            ; Determine ...
0040C1  2  1A              ina            ; ... next position
0040C2  2  25 7F           and   buf_idx_mask      ; Deal with index wrap
0040C4  2  C5 25           cmp   nx_rx_get_a      ; Compare with "get" index
0040C6  2  F0 06           beq   test_rhr_b      ; Buffer is full, drop datum
0040C8  2               ;
0040C8  2  85 27           sta   nx_rx_put_a      ; Set new "put" index
0040CA  2  98              tya            ; Recover and ...
0040CB  2  9D 00 20        sta   nx_rx_qa, X      ; Store datum
0040CE  2               ;
0040CE  2               ; vvvv  THIS WAS BASED ON PDF BY BDD  vvv
0040CE  2               ;   ldy   #msk_sr_rx_rdy      ; RHR status mask
0040CE  2               ;@process_datum:
0040CE  2               ;   tya
0040CE  2               ;   bit   IOBASE + dr_sra      ; Do we have anything in our RHR for
0040CE  2               ;   beq   test_rhr_b      ; channel A? Nope: go to B
0040CE  2               ;
0040CE  2               ;   lda   IOBASE + dr_rxfifoa   ; YES, read datum from RHR
0040CE  2               ;   ldx   nx_rx_put_a      ; RxD "put" index
0040CE  2               ;   inx            ; Increment
0040CE  2               ;   cpx   nx_rx_get_a      ; Compare with "get" index
0040CE  2               ;   beq   @process_datum      ; RxQ is full
0040CE  2               ;-----------------------
0040CE  2               ; If RxQ is full, the datum cannot be processed and is lost, corrupting the
0040CE  2               ; data stream. This should not happen is the frontend gets from RxQ in time
0040CE  2               ;-----------------------
0040CE  2               ;   dex            ; Realign RxD "put" index
0040CE  2               ;   sta   nx_rx_qa, X      ; Store datum into RxQ
0040CE  2               ;   inc   nx_rx_put_a      ; Increment RxD "put" index
0040CE  2               ;   bra   @process_datum      ; Loop for next
0040CE  2               ; ^^^ THIS WAS BASED ON PDF BY BDD ^^^
0040CE  2               test_rhr_b:
0040CE  2  A3 01           lda   irq_isrx, S
0040D0  2               @handle_rhr_b:
0040D0  2               ;
0040D0  2               ;-----------------------
0040D0  2               ; Test for channel A THR IRQ
0040D0  2               ;-----------------------
0040D0  2               test_thr_a:
0040D0  2  A3 01           lda   irq_isrx, S      ; Get ISR from stack
0040D2  2               ;
0040D2  2  89 01           bit   #msk_irq_txa      ; Did Xmitter A request interrupt?
0040D4  2  F0 20           beq   test_thr_b      ; Nope, try Xmitter B
0040D6  2               ;-----------------------
0040D6  2               ; Process channel A THR IRQ
0040D6  2               ;-----------------------
0040D6  2               @handle_thr_a:
0040D6  2  A6 26           ldx   nx_tx_get_a      ; Buffer "get" index
0040D8  2  E4 28           cpx   nx_tx_put_a      ; Compare with buffer "put" index
0040DA  2  D0 0E           bne   @get_datum
0040DC  2               ;
0040DC  2  A9 08           lda   #nx_cr_tx_dis      ; Disable TxD to suppress ...
0040DE  2  8D 02 C4        sta   IOBASE + dr_cra      ; ... interrupts
0040E1  2  A9 40           lda   #nx_txa_dis      ; Set xmitter disabled flag in
0040E3  2  0C 0C C4        tsb   IOBASE + dr_misc   ; - MISC register
0040E6  2  04 2D           tsb   nx_tx_status      ; - ZP (for debug)
0040E8  2  80 0C           bra   test_thr_b      ; Buffer is empty, so we can continue
0040EA  2               ;
0040EA  2               @get_datum:
0040EA  2  BD 00 21        lda   nx_tx_qa, X      ; Get datum from buffer
0040ED  2  8D 03 C4        sta   IOBASE + dr_txfifoa   ; Write to THR
0040F0  2  8A              txa            ; Current position
0040F1  2  1A              ina            ; New buffer position
0040F2  2  29 7F           and   #buf_idx_mask      ; Deal with wrap of index
0040F4  2  85 26           sta   nx_tx_get_a      ; Set new "get" index
0040F6  2               ;
0040F6  2               ; vvvv  THIS WAS BASED ON PDF BY BDD  vvv
0040F6  2               ;   ldx   nx_tx_get_a      ; Get current TxQ "get" index
0040F6  2               ;   ldy   #msk_sr_tx_rdy      ; THR status mask
0040F6  2               ;-----------------------
0040F6  2               ; Enter the loop to service the THR interrupt. This loop will continue until
0040F6  2               ; the THR is full or TxQ is empty
0040F6  2               ;-----------------------
0040F6  2               ;@next_datum:
0040F6  2               ;   cpx   nx_tx_put_a      ; Any (new) datums in TxQ?
0040F6  2               ;   beq   @tx_off         ; Nope, shutdown Xmitter and go to B
0040F6  2               ;
0040F6  2               ;   tya            ; YES ...
0040F6  2               ;   bit   IOBASE + dr_sra      ; Any space left in THR
0040F6  2               ;   beq   @done         ; no, done for now...
0040F6  2               ;-----------------------
0040F6  2               ; If the THR is full, the transmitter IRQ processing is done for now...
0040F6  2               ; Later on, when the THR's level has been reduced, another IRQ will occur and
0040F6  2               ; more datums can be processed
0040F6  2               ;-----------------------
0040F6  2               ;   lda   nx_tx_qa, X      ; Get datum from queue and ...
0040F6  2               ;   sta   IOBASE + dr_txfifoa   ; ... write to THR (FIFO)
0040F6  2               ;   inx            ; Increment "get" index
0040F6  2               ;   bra   @next_datum      ; And process next
0040F6  2               ;
0040F6  2               ;@tx_off:
0040F6  2               ;   lda   #nx_cr_tx_dis      ; Shutdown Xmitter A to suppress ...
0040F6  2               ;   sta   IOBASE + dr_cra      ; ... IRQs
0040F6  2               ;   lda   #nx_txa_dis      ; Set Xmitter A disbaled flag
0040F6  2               ;   tsb   IOBASE + dr_misc   ; Do in MISC register!
0040F6  2               ;   tsb   nx_tx_status      ; And in ZP (for debug)
0040F6  2               ;
0040F6  2               ;@done:
0040F6  2               ;   stx   nx_tx_get_a      ; Save final TxQ "get" index
0040F6  2               ; ^^^  THIS WAS BASED ON PDF BY BDD  ^^^
0040F6  2               ;
0040F6  2               test_thr_b:
0040F6  2  A3 01           lda   irq_isrx, S
0040F8  2               @handle_thr_b:
0040F8  2               
0040F8  2               ;
0040F8  2               ;-----------------------
0040F8  2               ; We have reached the end of our IRQ handler
0040F8  2               ;
0040F8  2               ; Clean stack from UART IRQ status
0040F8  2               ;-----------------------
0040F8  2  E2 30           shortr
0040FA  2  68              pla            ; Clear saved UART IRQ Status & discard
0040FB  2               ;
0040FB  2               nx_irq_end:
0040FB  2               ;
0040FB  2               ;-----------------------
0040FB  2               ; Clear stack and restore saved registers
0040FB  2               ;-----------------------
0040FB  2  C2 30           longr            ; 16 bit registers to recover
0040FD  2  7A              ply            ; .Y
0040FE  2  FA              plx            ; .X
0040FF  2  68              pla            ; .A
004100  2  E2 30           shortr
004102  2  2B              pld            ; Restore DP
004103  2  AB              plb            ; Restore DBR
004104  2               ;
004104  2               ;-----------------------
004104  2               ;   Contents of stack
004104  2               ; pushed by hardware
004104  2               ;irq_srreg   = 1         ; SR
004104  2               ;irq_pcreg   = irq_srreg + s_mpusrx   ; PC
004104  2               ;irq_pbreg   = irq_pcreg + s_mpupcx   ; PBR
004104  2  40              rti            ; Return from IRQ
004105  2               
004105  1                  .include   "init.asm"
004105  2               ;===============================================================================
004105  2               ;   A D R I A   - Philips/NXP 28L9x Initialization routine(s)
004105  2               ;
004105  2               ;    This source file holds the initialization routine(s) for the
004105  2               ;   Philips/NXP 28L9x IC.
004105  2               ;
004105  2               ;   Version history:
004105  2               ;      26 jan 2021 - Inital version
004105  2               ;===============================================================================
004105  2               ; nx_init - Initialize 28L9x environment
004105  2               ;
004105  2               ; Will read the configuration parameters from the table (bottom-up) and write
004105  2               ; them to the 29L9x.
004105  2               ;
004105  2               ; Currently the table is made for the 28L92 (2 ports), but this can be extended
004105  2               ; to the 8-port variant.
004105  2               ;
004105  2               ; Returns with carry cleared.
004105  2               ;-------------------------------------------------------------------------------
004105  2               nx_init:
004105  2  E2 30           shortr
004107  2  78              sei            ; Disable interrupts until done
004108  2               ;---------------------------------------
004108  2               ; We use register $0C (dr_misc) of the 28L9x as temporary storage
004108  2               ; and to indicate the driver initialization has succeeded. Initially we zero
004108  2               ; this register
004108  2  9C 0C C4        stz   IOBASE + dr_misc
00410B  2               ;
00410B  2               ; DEBUG
00410B  2               ;   jsr   NEWLINE
00410B  2               ; DEBUG
00410B  2               ;
00410B  2               ; Clear used/reserved zeropage (DP) locations
00410B  2               ;---------------------------------------
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
004114  2               ;
004114  2               ; Prepare jiffy counter
004114  2               ;---------------------------------------
004114  2  A9 64           lda   #hz
004116  2  85 20           sta   nx_jiffycnt
004118  2               ;
004118  2               ; Set up the 28L9x IC using the setup/lookup table
004118  2               ;---------------------------------------
004118  2  A0 42           ldy   #size_l92_suTable - 2   ; Get size of setup/lookup table
00411A  2               @setup:
00411A  2  BE 72 41        ldx   l92_suTable, Y      ; Read register offset
00411D  2  B9 73 41        lda   l92_suTable + s_byte, Y   ; Read register parameter
004120  2               ;
004120  2  9D 00 C4        sta   IOBASE, X      ; Write to register
004123  2               ; vvv DEBUG vvv
004123  2  84 40           sty   $40
004125  2  86 41           stx   $41
004127  2  85 42           sta   $42
004129  2               ;
004129  2  A5 40           lda   $40         ; Debug .Y
00412B  2  20 AD DF        jsr   DPYHEX
00412E  2  A9 2D           lda   #'-'
004130  2  20 0C FD        jsr   CHAR_OUT
004133  2               ;
004133  2  A5 41           lda   $41         ; Debug .X
004135  2  20 AD DF        jsr   DPYHEX
004138  2  A9 2D           lda   #'-'
00413A  2  20 0C FD        jsr   CHAR_OUT
00413D  2               ;
00413D  2  A5 42           lda   $42         ; Debug .A
00413F  2  20 AD DF        jsr   DPYHEX
004142  2  20 C4 DF        jsr   NEWLINE
004145  2               ;
004145  2  A5 42           lda   $42
004147  2  A6 41           ldx   $41
004149  2  A4 40           ldy   $40
00414B  2               ; ^^^ DEBUG ^^^
00414B  2  88              dey            ; As we use two bytes per register, ...
00414C  2  88              dey            ; ... we have to decrement .Y by 2
00414D  2  10 CB           bpl   @setup         ; Continue until we have reached top
00414F  2               ;
00414F  2               ; before we return, just point to our IRQ handler
00414F  2  C2 30           longr
004151  2  AD D8 02        lda   VECTOR_INT      ; Get original /IRQ vector
004154  2  85 2E           sta   rom_irq         ; Save it for later
004156  2               ;
004156  2  A9 8C 40        lda   #nx_irq         ; Install our new /IRQ vector
004159  2  AA              tax
00415A  2  49 AD DE        eor   #$DEAD         ; Calculate checksum (force invalid for
00415D  2                              ; now)
00415D  2  8D DA 02        sta   CHKSUM_INT      ; Store the checksum
004160  2  8E D8 02        stx   VECTOR_INT      ; Save the new vector
004163  2               ;
004163  2  E2 30           shortr            ; 8 bit registers
004165  2               ;
004165  2               ; Before we return we have to start the counter by reading IOBASE + dr_cnt_start
004165  2               ; As BDD mentioned, it might be safer to use a BIT instruction
004165  2               ;   lda   IOBASE + dr_cnt_start
004165  2  2C 0E C4        bit   IOBASE + dr_cnt_start
004168  2               ;
004168  2               ; Now we should get a 100Hz ticker and by enabling the interrupts (below), we
004168  2               ; should now have a 0.01 second clock timer ;)
004168  2               ;
004168  2               ; Before returning, set the nx_driver_init flag
004168  2  A9 80           lda   #nx_driver_init
00416A  2  0C 0C C4        tsb   IOBASE + dr_misc   ; Store this is the dr_misc register
00416D  2  04 2D           tsb   nx_tx_status
00416F  2               ;
00416F  2  58              cli            ; Enable interrupts
004170  2  18              clc            ; C is cleared, no error
004171  2  60              rts
004172  2               ;
004172  2               
004172  1                  .include   "tables.asm"
004172  2               ;===============================================================================
004172  2               ;   A D R I A   - Philips/NXP 28L9x Fixed data/reference/lookup tables
004172  2               ;
004172  2               ;   Version history:
004172  2               ;      26 jan 2021 - Inital version
004172  2               ;      08 feb 2020 - Changed Counter mode to Timer mode
004172  2               ;===============================================================================
004172  2               ; l92_suTable - 28L9x initialization sequence for two (2) ports
004172  2               ;---------------------------------------
004172  2               l92_suTable:            ; Philip/NXP 28L9x Initialization Table
004172  2               ;
004172  2               ; vvv  DEBUG  vvv
004172  2               ; Disabled IRQ for now, we have to start them manually)
004172  2  05 3B           .byte   dr_imr, nx_irq_msk   ; IMR (Enable IRQs)
004174  2               ;   .byte   dr_imr, msk_irq_ct   ; For testing, only enable CT IRQs
004174  2               ; ^^^  DEBUG  ^^^
004174  2               ;
004174  2  06 48           .byte   dr_ctu, nx_cnt_hi   ; CTU
004176  2  07 00           .byte   dr_ctl, nx_cnt_lo   ; CTL
004178  2               
004178  2  0A 0A           .byte   dr_crb, nx_cr_rxtx_dis   ; CRB - Disable RxD and TxD
00417A  2               ;---------------------------------------
00417A  2               ; Port B will be disabled, for now!
00417A  2               ;---------------------------------------
00417A  2               ;
00417A  2  09 CC           .byte   dr_csrb, nx_csr      ; CSR - Set Clock Register
00417C  2  08 17           .byte   dr_mrb, nx_mr2      ; MR2 - Set Mode Register 2
00417E  2  08 D3           .byte   dr_mrb, nx_mr1      ; MR1 - Set Mode Register 1
004180  2  0A 10           .byte   dr_crb, nx_cr_mr1   ; CRA - Select Mode Register 1
004182  2  08 C8           .byte   dr_mrb, nx_mr0      ; MR0 - Set Memory Register 0
004184  2  0A B0           .byte   dr_crb, nx_cr_mr0   ; CRA - Select Mode Register 0
004186  2               ;---------------------------------------
004186  2               ; Port B
004186  2               ;---------------------------------------
004186  2               ;
004186  2  02 80           .byte   dr_cra, nx_cr_rts_ass   ; CRA - Assert RTS
004188  2  02 05           .byte   dr_cra, nx_cr_rxtx_ena   ; CRA - Enable RxD and TxD
00418A  2               
00418A  2               ;   .byte   dr_cra, nx_cr_rxtx_dis   ; CRA - For now, disable RxD and TxD
00418A  2               ;
00418A  2               ;---------------------------------------
00418A  2               ; Enable port A
00418A  2               ;---------------------------------------
00418A  2               ;
00418A  2  01 CC           .byte   dr_csra, nx_csr      ; CSR - Set Clock Register
00418C  2  00 17           .byte   dr_mra, nx_mr2      ; MR2 - Set Mode Register 2
00418E  2  00 D3           .byte   dr_mra, nx_mr1      ; MR1 - Set Mode Register 1
004190  2  02 10           .byte   dr_cra, nx_cr_mr1   ; CRA - Select Mode Register 1
004192  2  00 C8           .byte   dr_mra, nx_mr0      ; MR0 - Set Memory Register 0
004194  2  02 B0           .byte   dr_cra, nx_cr_mr0   ; CRA - Select Mode Register 0
004196  2               ;---------------------------------------
004196  2               ; Port A
004196  2               ;---------------------------------------
004196  2               ;
004196  2  04 60           .byte   dr_acr, nx_acr_def   ; ACR - Auxiliary Control Register
004198  2               ;---------------------------------------
004198  2               ; ACR
004198  2               ;---------------------------------------
004198  2               ;
004198  2  0D F0           .byte   dr_opcr, nx_opcr_def   ; OPCR - Output Port Configuration Reg
00419A  2               ;---------------------------------------
00419A  2               ; OPCR
00419A  2               ;---------------------------------------
00419A  2               ;
00419A  2  0A C0           .byte   dr_crb, nx_cr_cnt_mod    ; CRB - Select C/T Counter mode
00419C  2  0A 40           .byte   dr_crb, nx_cr_err_res   ; CRB - Reset error status
00419E  2  0A 50           .byte   dr_crb, nx_cr_bir_res   ; CRB - Reset Received Break Change IRQ
0041A0  2  0A 30           .byte   dr_crb, nx_cr_tx_res   ; CRB - Reset transmitter
0041A2  2  0A 20           .byte   dr_crb, nx_cr_rx_res   ; CRB - Reset receiver
0041A4  2  0A 90           .byte   dr_crb, nx_cr_rts_dea    ; CRB - Deassert RTS
0041A6  2               ;---------------------------------------
0041A6  2               ; Init port B
0041A6  2               ;---------------------------------------
0041A6  2               
0041A6  2  02 C0           .byte   dr_cra, nx_cr_cnt_mod    ; CRA - Select C/T Counter mode
0041A8  2  02 40           .byte   dr_cra, nx_cr_err_res   ; CRA - Reset error status
0041AA  2  02 50           .byte   dr_cra, nx_cr_bir_res   ; CRA - Reset Received Break Change IRQ
0041AC  2  02 30           .byte   dr_cra, nx_cr_tx_res   ; CRA - Reset transmitter
0041AE  2  02 20           .byte   dr_cra, nx_cr_rx_res   ; CRA - Reset receiver
0041B0  2  02 90           .byte   dr_cra, nx_cr_rts_dea    ; CRA - Deassert RTS
0041B2  2               ;---------------------------------------
0041B2  2               ; Init port A
0041B2  2               ;---------------------------------------
0041B2  2               ;
0041B2  2  05 00           .byte   dr_imr, $00      ; IMR - Disable IRQs
0041B4  2  02 F0           .byte   dr_cra, nx_cr_pwr_up   ; CRA - Power up
0041B6  2               ;---------------------------------------
0041B6  2               ; Size of table
0041B6  2               ;---------------------------------------
0041B6  2               size_l92_suTable   = * - l92_suTable




Last edited by xjmaas on Thu Feb 11, 2021 9:15 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Thu Feb 11, 2021 7:22 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
I'm trouble reading your code due to the light contrast between the text and background (putting SIZE tags around the code, with SIZE=130, to make it larger may help). However, I will note one thing for now. The instruction at $004100 is unnecessary. The m and x bits in SR only affect .A, .X, .Y and R-M-W instructions. Hence the SHORTR macro will not influence the effect of the following PLD and PLB instructions. Furthermore, when the MPU pulls SR while executing RTI the m and x bits will be restored to their pre-interrupt settings.

You said something about "...stumbling upon an issue when sending large data sets." What would that issue be?

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Thu Feb 11, 2021 9:20 am 
Offline

Joined: Tue May 03, 2016 11:32 am
Posts: 41
I just resized the code block (and will try to remember to do so in the future!)

Thank you for the input, I will remove the shortr macro at that location (and save a few cycles).

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))


Top
 Profile  
Reply with quote  
PostPosted: Thu Feb 11, 2021 8:47 pm 
Offline

Joined: Tue May 03, 2016 11:32 am
Posts: 41
It looks like it has something to with the THR IRQ handler for channel A. But somehow I cannot seem to find it.

What happens:
When sending data, e.g. > 127 bytes of ASCII, the interrupt handler seems to "break" and hangs the computer. I have to /RESET to regain control. First I thought it had something to do with masking the index (to deal with wrapping). It seemed like the wrap was going over the 127 byte mark, so I changed bit 7 in the buf_idx_mask expression to 0. This seemed to help with manually sending > 127 bytes, about 16~32 bytes at a time.
When I try to send the header/info of "my bios", which is > 127 bytes, the issue happens.

Code:
buf_idx_mask   = s_e32_buf ^ %01111111   ; Buffer index wrap mask

...snip snip ....

;
;-----------------------   
; 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
;
; vvvv  THIS WAS BASED ON PDF BY BDD  vvv
;   ldx   nx_tx_get_a      ; Get current TxQ "get" index
;   ldy   #msk_sr_tx_rdy      ; THR status mask
;-----------------------
; Enter the loop to service the THR interrupt. This loop will continue until
; the THR is full or TxQ is empty
;-----------------------
;@next_datum:
;   cpx   nx_tx_put_a      ; Any (new) datums in TxQ?
;   beq   @tx_off         ; Nope, shutdown Xmitter and go to B
;
;   tya            ; YES ...
;   bit   IOBASE + dr_sra      ; Any space left in THR
;   beq   @done         ; no, done for now...
;-----------------------
; If the THR is full, the transmitter IRQ processing is done for now...
; Later on, when the THR's level has been reduced, another IRQ will occur and
; more datums can be processed
;-----------------------
;   lda   nx_tx_qa, X      ; Get datum from queue and ...
;   sta   IOBASE + dr_txfifoa   ; ... write to THR (FIFO)
;   inx            ; Increment "get" index
;   bra   @next_datum      ; And process next
;
;@tx_off:
;   lda   #nx_cr_tx_dis      ; Shutdown Xmitter A to suppress ...
;   sta   IOBASE + dr_cra      ; ... IRQs
;   lda   #nx_txa_dis      ; Set Xmitter A disbaled flag
;   tsb   IOBASE + dr_misc   ; Do in MISC register!
;   tsb   nx_tx_status      ; And in ZP (for debug)
;
;@done:
;   stx   nx_tx_get_a      ; Save final TxQ "get" index
; ^^^  THIS WAS BASED ON PDF BY BDD  ^^^


Top
 Profile  
Reply with quote  
PostPosted: Thu Feb 11, 2021 11:30 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
xjmaas wrote:
It looks like it has something to with the THR IRQ handler for channel A. But somehow I cannot seem to find it...

Just for fun, can you temporarily change your queue sizes to 256 bytes and just allow the queue indices to wrap? If that fixes it (which I suspect it will) then you need to carefully examine how you are wrapping the queue indices. I have to go out this evening but will see if I can look your code in detail when I return.

Also, there is a more efficient way to handle the two DUART channels in your interrupt service routine. If I'm not too tired when I return I'll post something about that.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 32 posts ]  Go to page 1, 2, 3  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 32 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: