Skip to content

Instantly share code, notes, and snippets.

@travisby
Created December 10, 2012 03:39
Show Gist options
  • Save travisby/4248251 to your computer and use it in GitHub Desktop.
Save travisby/4248251 to your computer and use it in GitHub Desktop.
Mapped Display with Interrupts Example For CUSP Assemby
.EQU @,$000 ;Initialize Program Counter
.EQU KBDCTRL,$000 ;Keyboard Control Port
.EQU KBDSTS,$000 ; Keyboard Status Port, same thing
.EQU KBDATA,$001 ;Keyboard Data Port
.EQU VDBUF,$101 ;Video Buffer's First Address (it's really the second, but it printed too close)
.EQU VDCTRL,$316 ;Video Control Port
.EQU VDDATA,$317 ;Video Data Port
.EQU HEIGHT,14 ;The height of CUSP's Screen
.EQU WIDTH,38 ;The Width of CUSP's Screen
.EQU LEN,5 ;The length I wanted each line to be
LDS $E00 ;Initialize Stack
LDX# 0 ;Load 0 into the XR, so we can use it for our mapped display. So we do video buffer + XR to get a point on the screen
SIE ;Enable the use of Interrupts in our application
LOOP: ;We return here every time a character is entered.
LDA# 255 ;This is "1111111" in binary. To tell the keyboard to "enable interrupt" and "clear buffer after use", we had to give it "11XXXXXX". The way I did this was by giving the largest binary value we could. Anything >=192 would have worked
OUTB KBDCTRL ;Send our message to the Keyboard Control. We want it to throw an interrupt when it has input, and clear the buffer afterwards
LDA# 0 ;This is part of the trickery for our interrupt wait routine. It's basically like polling.
STA ISDONE ;We save 0 into ISDONE, so we can continuously check it.
WAIT: ;You will see the interrupt ISR actually sets ISDONE to 1, so we break out of the loop then.
LDA ISDONE
CMA# 0
JEQ WAIT
;So, assume "ISR" has run by now. See that next. When the keyboard gets data, it calls ISR, no matter where in WAIT it is.
LDA KBVALUE ;Get our value from the keyboard that we saved in ISR
OUTB+ VDBUF ;Print it out to (video buffer + XR)
ADX# 1 ;Add 1 to the XR, so we move to the next character on our string
INC COUNT ;Increment count, to keep track of how many characters we have printed
LDA COUNT
MOD# LEN ;Compare COUNT to LEN. If it's divisible, go to a new line
CMA# 0
JEQ NEWLINE
JMP LOOP ;LET'S DO IT AGAIN!!!!
NEWLINE: ;This is some trickery for the mapped screen display
ADX# WIDTH-LEN ;We subtract LEN from the WIDTH, and add that to our current XR. This moves Y down a full position minus the length
JMP LOOP
HLT
ISDONE:.WORD 0 ;Used to track whether or not we have exited the Interrupt Service Routine
KBVALUE:.WORD 0 ;Stores the value we get from the keyboard
ISR:
LDA# 1
STA ISDONE ;Store 1 to break out of "WAIT" loop
INB KBDATA ;Get in from the keyboard
STA KBVALUE ;Save it
IRTN ;Super secret special return statement
.EQU @,$FF8 ;This is tricky. When a keyboard interrupt is thrown, it's going to call whatever program is in location FF8. So we put OUR program in FF8!
.WORD ISR ;That program is, "ISR". So now "ISR" is in $FF8. So when a KB interrupt is thrown, ISR is called.
COUNT: .WORD 0 ;Yeah... this is in the totes wrong place. But it works.
@travisby
Copy link
Author

There are a few improvements that could come to this program.

  • Add $FF8 into the symbol table at the beginning, and gave it a better name. Maybe something like "KBISR".
  • Move COUNT to the data section, rather than accidentally in location FF9. This is dangerously close to running out of memory
  • Find a better way to handle escaping from WAIT. I have a feeling this isn't how interrupts are supposed to work.
  • Line 17 could be changed to "128 + 64", so it is much easier to understand that we are attempting to turn on the first and second bit. We only used 255 since it encompassed all bits and we didn't have to do any math at first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment