Wednesday, August 23, 2017

Super Simple Super Serial Sample Source

     I have struggled to find the most basic of information about Apple II related machine coding information. Its not as freely available as people would like to have themselves believe it is. In searching, having often found the same struggles of others in the past, some who had given up years ago for lack of understanding or availability of information. While that is subjective, there is as it seems, a complete black hole with regard to several facets of the platform, much having to do with complications dealing with rom revs and later model incompatibilities compounded by different versions of software one might be running at the time and peripherals that might be attached. Even with information in front of you, its wrong, without context, that, being fragmented bits found in old newsgroups from Compuserve, leaves you worse for wear. Being a pampered Commodore guy, I am unencumbered by these issues, I don't deal with operating systems, I keep a computer in each and every disk drive, have a large support group and interface with the processor in its purest form except when workarounds for terrible implementations are required.

     Getting back to the Apple II, it would seem that one of the biggest offenders is the handling of interrupts.   Documentation of the past shows that the initial deployment didn't go very well at all. improvements were made, but subsequent OS control of interrupts further complicated matters.  Ive recently picked up a copy of Assembly lines, a wonderful reprint, thanks Chris, which i've referred to extensively in this project to translate the spoken Commodore into Applese, interesting point though, there is no mention of IRQ's or NMI's in that book. Probably for the aforementioned reasons. Given the book is a reprint, and IRQ kinda rolled out DOA, well..... anyway, to that end, I have slowly worked through old documentation, notes, more PRODOS crap than i'd ever care to know about and lots of debugging to provide a standard setup to build upon. Basically what I have at home, and use this going forward.

     The System is an Apple //e enhanced with an 80 column card providing 128K. The 80 column card and the extra 64k is of no consequence to this program. By default, I've included but commented out 80 column mode in the source code.  Im using Merlin 8 version 2.58 and added BASIC.SYSTEM to disk 2 so that BRUN could be employed for quicker development.  No emulation was used in this endeavor.  Final disks were pushed with ADTpro to a linux box, the source extracted for viewing here with Applecommander.

     The program is minimalist by design. Made to do as little as possible to meet the requirements set forth.  A connection is made to another computer via crossover cable running Minicom, Gtkterm or an equivalent.  The program starts with a blank screen.  Each key pressed on the Apple appears on both the apple and the distant end computer.  With the Apple, starting at the top left and advancing with each character.  When the distant end presses a key in will appear on the bottom row of the Apple starting at the bottom left and advancing to the right until the 15th character at which point it will start updating the bottom left again. A quasi visible ring buffer.  If you don't see a feature in this program its because it was not necessary.  SSC location detection, enhanced apple detection, split screen vector graphics support.... beyond the scope of this exercise.  WORKING SEND RECEIVE SSC ASSEMBLY LANGUAGE PROGRAM WITH PRODOS IRQ SUPPORT. THATS IT.

     The actual buffer that is offloaded from the SSC ACIA is in the zero page at $09.  The offloading portion is done during the IRQ.  That IRQ signal gets kicked off because of the SSC card receiving a byte, it doesn't mean the computer knows this program owns it.  Because the status register indicates such activity on the SSC itself, it can be tested in the IRQ code for ownership, acted upon or dismissed.   Nothing special about that, run of the mill ACIA stuff.  The fact that the IRQ code drops it in the BUFFER allows for the READBUFFER routine in the main program to test that zero page byte for new data and act upon it, keeping the heavy lifting out of the IRQ.

     So START clears the screen and initialized the SSC.  It also conducts some PRODOS voodoo to onboard the IRQ with its own identifier into one of 4 IRQ placeholders into PRODOS.  Ill admit i'm not a fan, this is not for the purist at heart.  But if you want mouse and disk drive support with your IRQ, well then....

     MAIN JSR'S to READBUFFER to see if its not #$00 to act upon it. If its #$00, wait for a keyboard event by jumping back to MAIN and getting stuck in this loop forever.

     There are only 2 ways out of this loop.   Press a key on the keyboard is the first.  If you press it it will appear on the screen, have the 7th bit removed from the byte and then a JSR to the SEND routine where it will check the STATUSREGISTER until it is ready to accept the byte,  once ready will send it off to the ACIA touch STROBE to clear that KEYSTROKE and loop back to MAIN

     The other way is for the IRQ to have left something in the BUFFER, that would make it no longer #$00.  If that is the case READBUFFER will pull that value out of the BUFFER and print it to $0750, AKA BOTTOM LEFT, offset by the COUNTER.   Once that value is printer the BUFFER is set back to #$00 and the COUNTER is incremented.  Should the counter reach #$15, the COUNTER will be set back to 0, completing the loop.  In either case , reset counter or not, the program will loop back to main once the receive byte is printed.

     I could further reduce the size of this program at the expense of readability and decide that it violated the goal of this exercise so I chose not to.  The parameters of which have already been stated.  So if anyone wants to provide a means for a new feature or make this smaller I have no interest whatsoever.  Should you find an outright bug of course, thats a different matter.  Furthermore, If anyone would like to provide some context with regard to the PRODOS IRQ onboarding voodoo as well as the bottom area labeled IRQLIST, that would be most welcomed.

     So,  did I need the IRQ.  Probably not.  I probably could have polled the STATUSREG if the timing was acceptable and program flow allowed up to a given speed.  Mileage varies.  At some point in a far extreme a case is to be made for NMI's which is a whole other business.  Another case is looking at the benefit of constant polling for data versus the SSC informing of an event and acting upon it external from the program.




DSK file is included below in google drive link as well as highlighted source.

Thank you and enjoy,

Jordan




Click here for PRODOS DSK file including Merlin source and executable



CONTENTS of SSCTEST.S
****************************************************
*         **** COMMODORE 64 BASIC V2 ****          *
*      64K RAM SYSTEM  38911 BASIC BYTES FREE      *
*     READY.                                       *
*     LOAD"SSCTEST",8,1                            *
****************************************************
*  Super Duper Simple SSC IRQ TEST                 *
*  Written and compiled natively on Merlin 8       *
*  No Emulators used...... TASM style formatting   *
*  Requires Apple IIe, most likely enhanced with   *
*  working interrupts and this code must also be   *
*  run from PRODOS to work...                      *
*  execute with --->          BRUN SSCTEST         *
*  Do not execute from the monitor                 *
*  Change SLOT value as necessary , set for 2      *
*  Default values are for N-8-1 9600 baud conn.    *
*  Transmit appears on top, RX buffer is a 15 byte *
*  rotating buffer within text memory on bottom of *
*  the screen.                                     *
*  Free for all to use - Jordan Rubin 2017         *
*  http://technocoma.blogspot.com                  *
*  More at www.youtube.com/c/JordanRubin6502       *
****************************************************
          ORG $2000      ; HIRES area unused and safe
COUNTER    = $08         ; Rotating counter for RXbyte
BUFFER     = $09         ; Where IRQ will store RXbyte
SLOT       = $20         ; This is slot 2 where SSC is
DATAREG     = $C088+SLOT
STATUSREG   = $C089+SLOT
COMMANDREG  = $C08A+SLOT
CONTROLREG  = $C08B+SLOT
HOME       = $FC58       ; CLS & Cursor to top POS
COUT       = $FDED       ; Like C64 $FFD2
KYBD       = $C000       ; Keyboard map point
STROBE     = $C010       ; Keyboard strobe map point
MLI        = $BF00       ; PRODOS MLI entry point

************** Start of program
START
                         ; JSR $C300 ; Uncomment for 80 COL
          JSR HOME       ; Clear screen
          JSR INIT       ; Run init for SSC Card

************** Main loop of program
MAIN
          JSR READBUFFER ; Read from where IRQ stores incoming
          LDA KYBD       ; Poll keyboard pointer
          CMP #$80       ; Check keyboard for activity
          BCC MAIN       ; Keep reading buffer till TXkey event
          JSR COUT       ; print TX locally on top of screen
          AND #$7F       ; shut off 7th bit for ESC issue
          JSR SEND       ; Send the byte to the ACIA outbound
          STA STROBE     ; Remove event by accessing
          JMP MAIN

************** CHECKS FOR CONTENT OF BUFFER AND PRINTS IT
READBUFFER
          LDA BUFFER     ; Pull Buffer content
          CMP #$00       ; Change since last initialization?
          BNE :PRINT     ; If so, go to PRINT routine
          RTS
:PRINT
          LDY COUNTER    ; Load COUNTER into Y
          INY            ; Increment it
          STA $0750,Y    ; Store BUFFER content to our screen bottom
          LDA #$00       ;              .......and offset by counter
          STA BUFFER     ; Reset Buffer to Null
          TYA            ; copy y to a
          CMP #$15       ; Are we on the Hex15 rotation
          BEQ RESETCOUNTER ; if so Reset the counter to 0
          STY COUNTER    ; if not store the counter
          RTS

RESETCOUNTER
          LDA #$00
          STA COUNTER    ; COUNTER is 0 again.....
          RTS

************** INIT Sets up the SSC and IRQ stuff
INIT
          LDA #$00
          STA STATUSREG
          STA COUNTER    ; set counter to 0
          JSR MLI        ; PRODOS ENTRY
          DB $40         ; MORE PRODOS
          DW IRQLIST     ; EVEN MORE PRODOS

********* LOAD VALUES INTO CONTROLREG
* BIT [7]    0 - ONE STOP BIT / 1 TWO STOP BITS
* BIT [6-5]  LENGTH - 8 (00) / 7 (01) / 6 (10) / 5 (11)
* BIT [4]    CLK - EXTERNAL (0) / INTERNAL (1)
* BIT [3-0]  BAUD - 9600 (1110) / 19.2K (1111)
*                   4800 (1100) / 2400  (1010)
******* USING N81 INTERNAL AT 9600 BAUD
          LDA #011110
          STA CONTROLREG

********* LOAD VALUES INTO COMMANDREG
* BIT [7-5] PARITY- (000)DIS  (001)O  (011)E  (101)M (111)S
* BIT [4]   ECHO -  (0) NORM / (1) ON
* BIT [3-2] TXINT- (00)DIS:RTSH (01)EN:RTSL
*                  (10)DIS:RTSL (11)DIS:SBRK
* BIT [1] RXINT - 0 ENABLED / 1 DISBLED
* BIT [0] DTR - 0 DISABLE RXTX,DTR HIGH / 1 ENABLE RXTX DTR LOW
********* USING RX INTERRUPTS ENABLED DTR LOW ENABLE RXTX
          LDA #001001
          STA COMMANDREG
          LDA DATAREG    ; Pull from DATAREG on init just because
          RTS

************** IRQ This is the IRQ code
IRQ
          CLD            ; Required by PRODOS
          LDA STATUSREG  ; Was it us who caused this interrupt
          BMI :ACTION    ; If so, Action!!!
          SEC            ; If not inform, not us....
          RTS
:ACTION
          LDA DATAREG    ; Load byte directly from dataregister
          STA BUFFER     ; and drop it in the ZP BUFFER
          CLC            ; clear interrupt
          RTS

************** SEND Check status and send a byte to ACIA
SEND
          TAY
:CHECK
          LDA STATUSREG  ; Load status register
          AND #$10       ; mask for ready bit
          BEQ :CHECK     ; not ready? keep checking
          STY DATAREG    ; ready?? store byte
          RTS

************** IRQLIST For PRODOS, overhead requirements
IRQLIST
          DB 2,0
          DW IRQ

No comments:

Post a Comment