Monday, September 11, 2017

Super Serial Switch Setting Status

     Ok, So I thought i'd bring this all together and try out just a few more tricks before moving onto something more comprehensive.  Having automatically identified the slot assignment and storing the value in zp SLOT $07 we can do some useful things with it by loading it into Y and using it as an offset when interfacing with the SSC as previously discussed.  As a demonstration, ive chosen not the command and control registers for this task, but the LS365 IC by which the physical DIP switches on the card are read into the registers as required.  That is to say, I do not want to know what the COMMAND and CONTROL values are.  I want to know what they WOULD BE, if read from those switches.   That said, not all of the individual switches are wired to the LS365; 3 of them are not connected, and in its stead, Clear to send has been added to one pin of the LS365 so its kinda weird.

The program starts off just like the previous one. Identifying which slot the SSC is found in...

Checking for SSC Card... Found in -->02

The next three values presented are Baud:, Mode:, and Data:.  I decided since this program was cut and dry that I might as well have some fun with this.  Ill forgo talking about how the labels for these three values appear in the program, it should be obvious through the course of code.   A quick note that there is some setcursor routines added to make the printout more manageable.

BAUD
The first order of business is BAUD and its settings reside in Switch 1, so we get the value of SWONE,Y (Y being the offset of SLOT) and store it to TESTBYTE, where we store switch values temporarily, because i'm about to do weird things to the value in the Accumulator throughout this program. I did something here to save a lot of code and cycles, so I shall explain.  BAUD takes up BITS 7 through 4 as saved in TESTBYTE and I don't care about anything else right now so we apply an AND mask of #$F0 to the Accumulator such that:

BITS    76543210  
VALUE   01101100
MASK    11110000
RESULT  01100000


Whatever the result is in the Accumulator, four ROR instructions are immediately issued to that result as shown below.

RESULT  01100000
ROR     00110000
ROR     00011000
ROR     00001100

ROR     00000110

     What is left is a 4 bit value that can be used in looking up the speed in the list of values in memory in the BAUDS/BAUDS2 label shown at the bottom portion of program memory.  Each speed is separated by a space character in the listing.  The code is reading that entire area of memory and looking for key value #$A0(space)as an index.  It will keep passing these spaces as many times as the value derived in the Accumulator, in this case, 6 times (0110) and then print the label until the next space character is reached, ending the print action.  If you look at BAUDS below and count 6 spaces and then start reading you will see that.


Checking for SSC Card... Found in -->02
                                       
   Baud: 300                           



MODE
The mode pulls TESTBYTE into the Accumulator, though it could really just re-pull from the switch, but that would mean re-initializing Y each time, so thats a consideration where every byte and cycle counts, so consider that.   Anyway.   Accumulator is loaded and another AND mask is conducted, this time #$03


BITS    76543210  
VALUE   01101100
MASK    00000011
RESULT  00000000


Now were only dealing with a 2 bit value with four possibilities. Using the same technique as bauds it is found on the bottom of memory, in the label of modes, four such possibilities separated by spaces to arrive at a printed value, such that:


Checking for SSC Card... Found in -->02
                                       
   Baud: 300                           
   Mode: Communication                 



DATA
The final value DATA is not one but 3 separate values tied together.  This requires information from switch 2, so SWTWO is now loaded into TESTBYTE and at the same time the Accumulator.

DATA - The STOP BIT

This is one boolean value, BIT 6 that determines if the STOP BIT is a 1 or a 2, so the value in the Accumulator will need a mask of #$40

BITS    76543210  
VALUE   01010000
MASK    01000000
RESULT  01000000


The value is boolean so there is no fancy code, a test if done after the mask,  if the Accumulator is holding #$40, print a 1, of not print a 2.   A quick print of #$AD after that just prints a dash '-' so that

   Data:  1-


DATA - The DATA BIT

For the Data bit, almost the exact same process, boolean value, pull TESTBYTE into Accumulator, but this time mask is #$10

BITS    76543210  
VALUE   01010001
MASK    00010000
RESULT  00010000


If the Accumulator is holding #$10, print an 8, if not print a 7, followed by #$AD for a dash so that
   Data:  1-8-



DATA - The PARITY

This again uses the same convention but has four possibilities for an output via testing and comparison.  The loading of TESTBYTE into the Accumulator follows a mask of #$0C

BITS    76543210  
VALUE   01010001
MASK    00001100
RESULT  00010000


A result of #$00 or #$08 will print an N, #$04 prints an O and #$0C will print an E, resulting in
   Data:  1-8-N


The final output of the program should appear as shown below.

Checking for SSC Card... Found in -->02
                                       
   Baud: 300                           
   Mode: Communication                 
   Data: 1-8-N                         
                                       



Link to DSK file with code and executable here



****************************************************
*         **** COMMODORE 64 BASIC V2 ****          *
*      64K RAM SYSTEM  38911 BASIC BYTES FREE      *
*     READY.                                       *
*     LOAD"SSCSETTINGS",8,1                        *
****************************************************
*  ---Pulls the settings from the DIP switches---  *
*  This program builds off of the auto detect code *
*  to read the information off of the two DIP      *
*  switches and decipher the values into human     *
*  readable form reporting back to the screen      *
*  Note that not all switches are tied logically   *
*  and are wired through an LS365. 3 to be exact.  *
*  SW2-6, interrupts, SW1-7 and SW2-7 for the DCD. *
*  Existing but not written in this program is the *
*  state of CTS which can be read from SWTWO       *
*  Written and compiled natively on Merlin 8       *
*  No Emulators used...... TASM style formatting   *
*  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
COUT       = $FDED       ; Like C64 $FFD2
CH         = $24         ; Cursor Horizontal
CV         = $25         ; Cursor Vertical
PRBYTE     = $FDDA       ; HEXPRINT
TESTBYTE   = $0A         ; test byte area
LSB        = $08         ; Bottom half of memory address
MSB        = $09         ; Top half of memory address
HOME       = $FC58       ; CLS and Cursor to top POS
SLOT       = $07         ; Testing and storage of slot
DATAREG    = $C088       ; Needs slot added when called
STATUSREG  = $C089       ; Needs slot added when called
COMMANDREG  = $C08A      ; Needs slot added when called
CONTROLREG  = $C08B      ; Needs slot added when called
SWONE      = $C081       ; Needs slot added when called
SWTWO      = $C082       ; Needs slot added when called

************** Start of program
START
          JSR  HOME      ; Clear screen, and top left start
          LDY #$00

************** Prints Message on top of screen
PRINTMESSAGE
          LDA MESSAGELABEL,Y
          JSR COUT
          INY
          CPY #$19
          BNE PRINTMESSAGE

************** Init routine start at slot one and MSB C1
INIT
          LDA #$01       ; Starting slot is 1
          STA SLOT       ; Store it
          LDA #$C1       ; Starting MSB is C1
          STA MSB        ; Store it
          LDX #$00       ; Init X

************** The main testing routine
ROUTINE
          LDA LSBVAL,X   ; LSB comes from data at at LSBVAL
          STA LSB        ; For each x - 05, 07, 0B, 0C
          LDY #$00       ; We dont want an offset for this action
          LDA (LSB),Y    ; Cs05 content load, indirect index
          STA TESTBYTE   ; Store return to temp memory area
          LDA SSCID,X    ; Load expected SSCID value for x to a
          CMP TESTBYTE   ; Compare recieved value to a
          BNE NEXTSLOT   ; Not equal? Not an SSC, try next slot
          INX            ; Equal? X++
          CPX #$03       ; All four bytes passed?
          BEQ FOUND      ; We have found the SSC!!!
          JSR ROUTINE    ; Not four yet, repeat routine....

************** Action to proceed to next slot to test
NEXTSLOT
          LDX SLOT       ; Load current slot into X
          INX            ; Increment it
          CPX #$07       ; Passed the last slot to test
          BEQ GIVEUP     ; Give up, no SSC found....
          STX SLOT       ; Store new current slot value
          LDX MSB        ; load current MSB into X
          INX            ; Increment it
          STX MSB        ; Store it
          LDX #$00       ; Init X
          JSR ROUTINE    ; Try Routine again

************** What to do when no SSC is found
GIVEUP
          LDX #$00       ; Init X
:PR
          LDA NOTFOUND,X ; Print not found Label
          JSR COUT
          INX
          CPX #$0D
          BNE :PR
          JMP $3D0       ; Back to Basic

************** When an SSC is found

FOUND
          LDX #$00       ; Init X
:PR
          LDA FOUNDLABEL,X ; Print found label
          JSR COUT
          INX
          CPX #$0D
          BNE :PR
          LDA SLOT
          JSR PRBYTE     ; Print slot num to screen
          LDA SLOT       ; Load SLOT into A
          ROL
          ROL
          ROL
          ROL            ; Multiply by 0x10
          STA SLOT       ; Store slot into A, official slot value!
          LDY SLOT
          LDA SWONE,Y
          STA TESTBYTE
          AND #%11110000
          ROR
          ROR
          ROR
          ROR
          STA LSB

DISPVALS
          LDX #$03       ; Horiz offset
          LDY #$03       ; Vert offset
          JSR SETCURSOR  ; set
          LDX #$00
:PR
          LDA BAUDLABEL,X
          JSR COUT
          INX
          CPX #$06
          BNE :PR

BAUDRATE
          LDX #$00
          LDY #$00
:INDEXLOOP
          CPX LSB
          BEQ :PRINTBAUD
:TEST
          LDA  BAUDS,Y
          INY
          CMP #$A0
          BNE :TEST
          INX
          JSR :INDEXLOOP
:PRINTBAUD
          TYA
          TAX
          INY
:PR
          LDA BAUDS,X
          JSR  COUT
          INX
          CMP #$A0
          BNE :PR
MODESTEP
          LDX #$04
          LDY #$03
          JSR SETCURSOR
          LDX #$00
:PR
          LDA MODELABEL,X
          INX
          JSR COUT
          CPX #$06
          BNE :PR
          LDA TESTBYTE
          AND #000011
          STA LSB
MODE
          LDX #$00
          LDY #$00
:INDEXLOOP
          CPX LSB
          BEQ :PRINTMODE
:TEST
          LDA MODES,Y
          INY
          CMP #$A0
          BNE :TEST
          INX
          JSR :INDEXLOOP
:PRINTMODE
          TYA
          TAX
          INY
:PR
          LDA MODES,X
          JSR COUT
          INX
          CMP #$A0
          BNE :PR
NEXTSWITCH
          LDY SLOT
          LDA SWTWO,Y
          STA TESTBYTE
          AND #%01000000
          STA LSB
          LDX #$05
          LDY #$03
          JSR SETCURSOR
          LDX #$00
:PR
          LDA DATALABEL,X
          JSR COUT
          INX
          CPX #06
          BNE :PR
          LDA LSB
          CMP #$40
          BEQ :PRONE
          JSR :PRTWO
:PRONE
          LDA #$B1
          JSR :PROUT
:PRTWO
          LDA #$B2
          JSR :PROUT
:PROUT
          JSR COUT
          LDA #$AD
          JSR COUT
DBITS
          LDA TESTBYTE
          AND #010000
          CMP #$10
          BEQ :PREIGHT
          JSR :PRSEVEN
:PREIGHT
          LDA #$B8
          JSR :PROUT
:PRSEVEN
          LDA #$B7
          LSR :PROUT
:PROUT
          JSR COUT
          LDA #$AD
          JSR COUT
FORMAT
          LDA TESTBYTE
          AND #001100
          CMP #$00
          BEQ :N
          CMP #$08
          BEQ :N
          CMP #$04
          BEQ :O
          CMP #$0C
          BEQ :E
:N
          LDA #$CE
          JSR COUT
          JSR ENDLOOP
:O
          LDA #$CF
          JSR COUT
          JSR ENDLOOP
:E
          LDA #$C5
          JSR COUT
          JSR ENDLOOP

SETCURSOR
           STX  CV
          JSR $FD8E
          STY CH
          RTS

ENDLOOP
          JSR ENDLOOP

MESSAGELABEL ASC "Checking for SSC Card... "
FOUNDLABEL ASC "Found in --> "
NOTFOUND  ASC "Was not found"
SSCID      HEX 38,18,01,31 ; 4 identifying bytes for SSC
LSBVAL     HEX 05,07,0B,0C ; LSB for identifying memory areas
BAUDLABEL  ASC "Baud: "
MODELABEL  ASC "Mode: "
DATALABEL  ASC "Data: "
BAUDS      ASC "External 50 75 110 135 150 300 600 1200 "
BAUDS2     ASC "1800 2400 3600 4800 7200 9600 19,200"
MODES      ASC "COMMUNICATION SICP8EM PRINTER SICP8AEM"

Wednesday, August 30, 2017

Super Serial Makes a Personal Discovery




   This seems like the next possible task for such a device. I've kept a yellow post-it note under the monitor with a listing of what card resides in which slot and have often lost it. Having to then remove the monitor to retake inventory of the system.  This seemed like a good time for the next evolution of code, definitely not as complicated as the IRQ issue, but requiring some thought, none the less.

     I have a copy of Apples SSC manual, both versions of the manual which i refer to as the crappy consumer grade and the deluxe engineering version.  They both discuss card identification by way of four bytes that will appear in predictable locations of memory. This further matches up with the Apple IIe technical reference manual on page 278; in short....
                             $Cs05 = 38
                             $Cs07 = 18
                             $Cs0B = 01
                             $Cs0C = 31           Where s = the slot number

     I figured there must be code out there already, but I wanted to take a crack at this without influence. So I though to myself all I need is a process which starts at slot 1 and tries to read 38 from $C105 if it does, then it tries to read 18 from $C107. If that works try to read 01 from $C10B and finally 31 from $C10C.  Should any of the expected values not come back during this test at any time go to the next slot and start this test all over, till you run out of slots, then give up.  If you do make it through all four numbers, well then, you've found your SSC card!

     As I started thinking about this I realized that there are 7 slots to test with four cycles each, that's a large volume of assembly code for slot detection. Actually 28 possible iterations.  After getting one full cycle working in this longhand method I constructed a more efficient design.  Quite clever actually.

     In the INIT portion the value SLOT is set to 01 and the MSB is set to C1 for the first slot.  The MSB need only be incremented along with the slot value to move to the next slot to test. So the next increment would have the SLOT at 02 and the MSB at C2. and so on until 07 and C7 as the last one.

At the bottom of the program is the storage of 8 bytes of data, its relevance is shown below

INDEX(X) 0     1     2     3

---------------------------------                                              
SSCID  38 18 01 31    Expected return data from memory address 
LSBVAL 05 07 0B 0C    Least significant byte of that address


Now we see that labels LSB and MSB sit next to each other in the zeropage.

LSB        = $08         ; Bottom half of memory address
MSB        = $09         ; Top half of memory address

So with a small routine using the same X as an index to pull from SCCID as well as LSBVAL I can get both the answer im looking for as well as the other half of the memory address I need to pull that answer.

MSB     =   C1    already stored in $09 from INIT
LSB     =   05    Pulled from LSBVAL index 0, stored in $08
SSCID   =   38    Expected answer SSCID index 0
      LDY #$00 ; no offset
      LDA (LSB),Y    =  LDA (C1&05),0   =   LDA $C105


The value coming back into a is stored in TESTBYTE so that SSCID loaded into a can be compared against TESTBYTE to see if they are the same value.  If they are, in this case 38,  ONLY X IS INCREMENTED and the cycle is repeated, this time...

MSB     =   C1    already stored in $09
LSB     =   07    Pulled from LSBVAL index 1, stored in $08
SSCID   =   18    Expected answer SSCID index 1
      LDY #$00 ; no offset
      LDA (LSB),Y    =  LDA (C1&07),0   =   LDA $C107


     Again, if X should make it to the 4th interval, then the card is found and the program will jump out to FOUND.  If there is no match X will reset back to zero and the MSB and SLOT will be incremented, this process starts all over.

     If the card is found, more code below displays the slot number to the screen and a simple indication that it has been found.  also, 4 ROL multiply the slot number by 0x10 (dec16) and store it back into slot. All of the previously mentioned connections into to the ACIA are listed here without any offset onto of the program as shown

DATAREG     = $C088       ; Needs slot added when called
STATUSREG   = $C089       ; Needs slot added when called
COMMANDREG  = $C08A       ; Needs slot added when called
CONTROLREG  = $C08B       ; Needs slot added when called

 To access them in a program, The offset in SLOT would have to be loaded into Y and then used as an offset in the call.  Considering sending a byte to the ACIA as data:

            LDY SLOT                              
            STA DATAREG,Y  

     So was all of this worth it from a memory perspective?  In consideration that almost half of the example program below is just printing some sort of output to the screen in the spirit of view-ability the total number of bytes ACTUALLY NEEDED to run this program, and assign the SLOT and move onto the next item is just 77 Bytes.  By comparison, simply storing the text "Please specify the slot of your SSC card: " to memory takes up 42 bytes all by itself, the code to print it to the screen takes at least 12 bytes, now were at 54 bytes,  then the KEYIN, strobe, associated validation checking of the human input, math to do all of the same conversion and assignment to the SLOT, testing and deployment. Also, what if the wrong number was given, is there exception handling? No doubt it would be way over 77 bytes for a program that has a manual entry no auto discovery and the propensity for human error.

     Its worth noting that in either case, if such a program were being constructed that every last byte had to be accounted for, there is no reason why all of this detection code couldn't simply be copied over by the main program after the fact, having stored the correct location in SLOT, none of the detection code has any further practical use in memory once the task is completed.  The last action in FOUND could tell PRODOS to load and execute a MAIN.bin application who's ORG = $2000 effectively copying directly over all of this on load.





Click here for PRODOS DSK file including Merlin source and executable



****************************************************
*         **** COMMODORE 64 BASIC V2 ****          *
*      64K RAM SYSTEM  38911 BASIC BYTES FREE      *
*     READY.                                       *
*     LOAD"SSCFINDER",8,1                          *
****************************************************
*      ---Auto detecting SSC card code---          *
*  Written and compiled natively on Merlin 8       *
*  No Emulators used...... TASM style formatting   *
*  Uses 4 known bytes of data that the SSC will    *
*  return if the offset for the memory address     *
*  matches the slot the SSC is in. Those SSCID's   *
*  & corresponding LSB's are loaded together in    *
*  the same loop iteration to keep the code very   *
*  small, only the MSB increments to change the    *
*  card. LSB and MSB are used as (LSB),msb to call *
*  the individual addresses to read.               *
*  Once found SLOT is multiplied by 0x10 and then  *
*  Re-stored in SLOT for use as an offset value    *
*  for DATAREG, COMMAND and CONTROL                *
*            LDY SLOT                              *
*            STA DATAREG,Y                         *
*  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
COUT        = $FDED       ; Like C64 $FFD2
PRBYTE      = $FDDA       ; HEXPRINT
TESTBYTE    = $0A         ; test byte area
LSB         = $08         ; Bottom half of memory address
MSB         = $09         ; Top half of memory address
HOME        = $FC58       ; CLS & Cursor to top POS
SLOT        = $07         ; Testing and storage of slot
DATAREG     = $C088       ; Needs slot added when called
STATUSREG   = $C089       ; Needs slot added when called
COMMANDREG  = $C08A       ; Needs slot added when called
CONTROLREG  = $C08B       ; Needs slot added when called

************** Start of program
START
          JSR HOME       ; Clear screen, and top left start
          LDY #$00

************** Prints Message on top of screen
PRINTMESSAGE
          LDA MESSAGELABEL,Y
          JSR COUT
          INY
          CPY #$19
          BNE PRINTMESSAGE

************** Init routine start at slot one and MSB C1
INIT
          LDA #$01       ; Starting slot is 1
          STA SLOT       ; Store it
          LDA #$C1       ; Starting MSB is C1
          STA MSB        ; Store it
          LDX #$00       ; Init X

************** The main testing routine
ROUTINE
          LDA LSBVAL,X   ; LSB comes from data at at LSBVAL
          STA LSB        ; For each x - 05, 07, 0B, 0C
          LDY #$00       ; We dont want an offset for this action
          LDA (LSB),Y    ; Cs05 content load, indirect index
          STA TESTBYTE   ; Store return to temp memory area
          LDA SSCID,X    ; Load expected SSCID value for x to a
          CMP TESTBYTE   ; Compare recieved value to a
          BNE NEXTSLOT   ; Not equal? Not an SSC, try next slot
          INX            ; Equal? X++
          CPX #$03       ; All four bytes passed?
          BEQ FOUND      ; We have found the SSC!!!
          JSR ROUTINE    ; Not four yet, repeat routine....

************** Action to proceed to next slot to test
NEXTSLOT
          LDX SLOT       ; Load current slot into X
          INX            ; Increment it
          CPX #$07       ; Passed the last slot to test
          BEQ GIVEUP     ; Give up, no SSC found....
          STX SLOT       ; Store new current slot value
          LDX MSB        ; load current MSB into X
          INX            ; Increment it
          STX MSB        ; Store it
          LDX #$00       ; Init X
          JSR ROUTINE    ; Try Routine again

************** What to do when no SSC is found
GIVEUP
          LDX #$00       ; Init X
:PR
          LDA NOTFOUND,X ; Print not found Label
          JSR COUT
          INX
          CPX #$0D
          BNE :PR
          JMP $3D0       ; Back to Basic

************** When an SSC is found
FOUND
          LDX #$00       ; Init X
:PR
          LDA FOUNDLABEL,X ; Print found label
          JSR COUT
          INX
          CPX #$0D
          BNE :PR
          LDA SLOT
          JSR PRBYTE     ; Print slot num to screen
          LDA SLOT       ; Load SLOT into A
          ROL
          ROL
          ROL
          ROL            ; Multiply by 0x10
          STA SLOT       ; Store slot into A, official slot value!
          JMP $3D0       ; Back to Basic

MESSAGELABEL ASC "Checking for SSC Card... "
FOUNDLABEL   ASC "Found in --> "
NOTFOUND     ASC "Was not found"
SSCID        HEX 38,18,01,31 ; 4 identifying bytes for SSC
LSBVAL       HEX 05,07,0B,0C ; LSB for identifying memory areas

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