improve documentation
This commit is contained in:
parent
d86ac8d52d
commit
7fce58e481
@ -289,11 +289,12 @@ TAB_SIZE = 4
|
||||
# with the commands \{ and \} for these it is advised to use the version @{ and
|
||||
# @} or use a double escape (\\{ and \\})
|
||||
|
||||
ALIASES = "modifies=\xrefitem modifies \"Modifies Registers\" \"Modified Registers\"" \
|
||||
ALIASES = "modifies=\par Modifies Registers^^" \
|
||||
"type=\xrefitem type \"Code Type\" \"Code Type\"" \
|
||||
"macro=\qualifier macro \brief" \
|
||||
"function=\qualifier subroutine \brief" \
|
||||
"module=\file ^^ \brief"
|
||||
"module=\file ^^ \brief" \
|
||||
"clock_dependant=\xrefitem clock_dependant \"Clock Speed Dependance\" \"Clock frequency dependant code\""
|
||||
|
||||
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
|
||||
# only. Doxygen will then generate output that is more tailored for C. For
|
||||
@ -529,7 +530,8 @@ TIMESTAMP = NO
|
||||
# normally produced when WARNINGS is set to YES.
|
||||
# The default value is: NO.
|
||||
|
||||
EXTRACT_ALL = NO
|
||||
# TODO Document everyhing
|
||||
EXTRACT_ALL = YES
|
||||
|
||||
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
|
||||
# be included in the documentation.
|
||||
@ -954,7 +956,7 @@ WARN_LOGFILE =
|
||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = . build programs system util
|
||||
INPUT = . build programs system util .extra_docs.s65 doxy-asm65.py
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
@ -994,10 +996,8 @@ INPUT_FILE_ENCODING =
|
||||
# be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
|
||||
# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
|
||||
|
||||
FILE_PATTERNS = *.cpp \
|
||||
*.s65 \
|
||||
*.h65 \
|
||||
*.md
|
||||
FILE_PATTERNS = *.s65 \
|
||||
*.h65
|
||||
|
||||
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
||||
# be searched for input files as well.
|
||||
@ -1124,7 +1124,7 @@ FILTER_SOURCE_PATTERNS =
|
||||
# (index.html). This can be useful if you have a project on for instance GitHub
|
||||
# and want to reuse the introduction page also for the doxygen output.
|
||||
|
||||
USE_MDFILE_AS_MAINPAGE = #../README.md
|
||||
USE_MDFILE_AS_MAINPAGE =
|
||||
|
||||
# The Fortran standard specifies that for fixed formatted Fortran code all
|
||||
# characters from position 72 are to be considered as comment. A common
|
||||
@ -1364,7 +1364,7 @@ HTML_STYLESHEET =
|
||||
# documentation.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_EXTRA_STYLESHEET = #../docs/doxygen-awesome-css/doxygen-awesome.css
|
||||
HTML_EXTRA_STYLESHEET = ../docs/custom/doxygen-awesome.css
|
||||
|
||||
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
|
||||
# other source files which should be copied to the HTML output directory. Note
|
||||
|
67
.extra_docs.s65
Normal file
67
.extra_docs.s65
Normal file
@ -0,0 +1,67 @@
|
||||
;;********************************************************************************
|
||||
;; @mainpage 8-bit Breadboard Computer with W65C02S Processor
|
||||
;; This repo contains the assembly code for my [6502-project](https://quintern.xyz/de/posts/2021_6502).
|
||||
;;
|
||||
;; The assembler used for this project is the excellent [ca65](https://github.com/cc65/cc65).
|
||||
;; After assembling it, the binary is loaded onto the EEPROM using [my *eeprom.py* script](https://git.quintern.xyz/MatthiasQuintern/AT28C256-rpi-util) on a Raspberry Pi 4B.
|
||||
;;
|
||||
;; @section main_os Operating System
|
||||
;; ... is probably a far stretch, since it is just the programs I wrote pieced together. My "OS" consists of these functionalities:
|
||||
;; - Supported Hardware:
|
||||
;; - 4x4 Matrix Keypad
|
||||
;; - 4x16 Characters LCD Display
|
||||
;; - PS/2 Keyboard
|
||||
;; - SPI Connection to an Arduino
|
||||
;; - Software
|
||||
;; - @ref ps2_keyboard_printer "Keyboard" and @ref keypad_printer "keypad printer": Prints the characters you press on to the lcd
|
||||
;; <!-- - Temperature: Shows the temperature using a dht sensor. *Work in progress, this does not work yet* -->
|
||||
;; - @ref print_slow "(Stylishly)" print @ref "str::strf" "formated strings" to the LCD
|
||||
;; - @ref sleep "Sleep"
|
||||
;; - Send @ref ps2_keyboard_util "various commands" to the keyboard
|
||||
;; - @ref ringbuffer "Ringbuffer"
|
||||
;;
|
||||
;; > It's not much, but it's honest work.
|
||||
;;
|
||||
;; @section main_hardware Hardware details
|
||||
;; @subsection main_hw_addr Address Space
|
||||
;; |Name|From|To|r/w|
|
||||
;; |---|---:|---:|:---:|
|
||||
;; |ZEROPAGE |$00 |$ff |`rw`|
|
||||
;; |STACK |$100 |$1ff |`rw`|
|
||||
;; |RAM |$200 |$4fff |`rw`|
|
||||
;; |SPI |$5000 |$5fff |`rw`|
|
||||
;; |VIA1 |$6000 |$600f |`rw`|
|
||||
;; |VIA2 |$7000 |$700f |`rw`|
|
||||
;; |ROM |$8000 |$ffff |`r `|
|
||||
;;
|
||||
;;
|
||||
;; @section main_software Software details
|
||||
;; @subsection main_sw_naming Naming conventions
|
||||
;; leading underscors `_` indicate a "private" label/variable, that is meant for internal use within the module only.
|
||||
;;
|
||||
;; **Labels**:
|
||||
;; - **scopes**: snake case
|
||||
;; - **subroutines** and **variables**: snake case (`scope::(_)fname_snake_case` or `scope::(_)varname_2`)
|
||||
;; - **macros**: camel case (`(_)GoodMacroname` or `scope_GoodMacroname`)
|
||||
;; - **constants** (eg. in ROM): upper case (`scope::(_)NICE_SYMBOLNAME`)
|
||||
;; - **enums**: upper case (`scope::(_)ENUM_NAME::ENUM_MEMBER`)
|
||||
;;********************************************************************************
|
||||
|
||||
;;********************************************************************************
|
||||
;; @defgroup applications
|
||||
;; @brief Applications that do ... *something*
|
||||
;;
|
||||
;;********************************************************************************
|
||||
|
||||
;;********************************************************************************
|
||||
;; @defgroup drivers
|
||||
;; @brief Code that handles a physical device
|
||||
;;
|
||||
;;********************************************************************************
|
||||
|
||||
;;********************************************************************************
|
||||
;; @defgroup utility
|
||||
;; @brief Code that does something useful and is intended to be used in other code
|
||||
;;
|
||||
;;********************************************************************************
|
||||
|
19
details.md
19
details.md
@ -1,19 +0,0 @@
|
||||
# Project details
|
||||
## Address Space
|
||||
|Name|From|To|r/w|
|
||||
|---|---:|---:|:---:|
|
||||
|ZEROPAGE |$00 |$ff |`rw`|
|
||||
|STACK |$100 |$1ff |`rw`|
|
||||
|RAM |$200 |$4fff |`rw`|
|
||||
|SPI |$5000 |$5fff |`rw`|
|
||||
|VIA1 |$6000 |$600f |`rw`|
|
||||
|VIA2 |$7000 |$700f |`rw`|
|
||||
|ROM |$8000 |$ffff |`r `|
|
||||
|
||||
## Naming conventions
|
||||
leading underscors `_` indicate a "private" label/variable, that is meant for internal use within the module only.
|
||||
### Labels
|
||||
- **scopes**: snake case
|
||||
- **subroutines** and **variables**: snake case (`scope::(_)fname_snake_case` or `scope::(_)varname_2`)
|
||||
- **macros**: camel case (`(_)GoodMacroname` or `scope_GoodMacroname`)
|
||||
- **constants** (eg. in ROM): upper case (`scope::(_)NICE_SYMBOLNAME`)
|
@ -2,6 +2,37 @@ import sys
|
||||
import re
|
||||
from typing import Callable
|
||||
|
||||
##
|
||||
# @defgroup documentation Documentation
|
||||
# @brief
|
||||
#
|
||||
|
||||
##
|
||||
# @file
|
||||
# @brief Doxygen filter for ca65 assembler files
|
||||
# @details
|
||||
# This filter converts ca65 to C++ statements that doxygen can parse.
|
||||
#
|
||||
# Doxygen comments are double semicolons `;;`
|
||||
# - turns procedures `.proc` into function statements with `proc` as return type
|
||||
# Parameters documented with the @param command are put into the paranthesis (function arguments) with `Param` as type (@ref handle_procedure)
|
||||
# - turns macros `.macro` into function statements with `macro` as return type with the parameter macros
|
||||
# as function arguments with `Param` type (@ref handle_procedure)
|
||||
# - enums become ... enums, documentation of enum members after their name is also handled (@ref handle_procedure)
|
||||
# - labeled storage allocations with `.byte`, `.res`, `.ascii` etc. are turned into variable declarations with the label as variable name (@ref handle_procedure)
|
||||
# - if allocations are strings, they are concatenated together to `char * LABEL_NAME = "<string(s)>";`
|
||||
# - if there are multiple non-string allocations: `bytes LABEL_NAME[] = {alloc1, alloc2, ...};`
|
||||
# - if there is one non-string allocation: `alloc_type * LABEL_NAME = alloc;`
|
||||
# - if the allocation is not initilized: `alloc_type * LABEL_NAME;`
|
||||
# - if the allocation type is `res SIZE`: `bytes LABEL_NAME[SIZE];`
|
||||
# - the sizes of the arrays may be wrong!
|
||||
# - include statements are kept
|
||||
# - all other preprocessor macros are removed
|
||||
#
|
||||
# @todo Handle structs
|
||||
# @todo for storage allocators, check in which segment they are in and apply `const` where necessary
|
||||
# @ingroup documentation
|
||||
|
||||
filename = "unknown"
|
||||
|
||||
def pdebug(*args, **k):
|
||||
@ -16,7 +47,7 @@ def parse_custom_language(file_content: str):
|
||||
scope = m.groups()[1]
|
||||
functions = m.groups()[2].replace(" ", "").strip(",")
|
||||
for f in functions.split(","):
|
||||
pdebug(f"Add Exported function: '{f}' in '{scope}'")
|
||||
# pdebug(f"Add Exported function: '{f}' in '{scope}'")
|
||||
exported_names[f] = scope
|
||||
return ""
|
||||
|
||||
@ -50,12 +81,11 @@ def parse_custom_language(file_content: str):
|
||||
if s[-1] == ",": s = s[:-1]
|
||||
s += ");\n"
|
||||
elif p_type == "macro":
|
||||
pdebug(f"Processing macro '{p_name}' with args '{'TXT'.join(p_args.replace(' ', '').split(','))}'")
|
||||
# pdebug(f"Processing macro '{p_name}' with args '{'TXT'.join(p_args.replace(' ', '').split(','))}'")
|
||||
s += f"macro {p_name}("
|
||||
p_args = "".join("Param " + param + "," for param in p_args.replace(" ", "").split(',')).strip(",")
|
||||
s += p_args
|
||||
s += ");\n"
|
||||
pdebug("Found macro", p_name, s)
|
||||
elif p_type == "enum":
|
||||
p_code = re.sub(r"( *(?:;;.*)?\n)", r",\1", p_code)
|
||||
s += f"enum {p_name}" + "{\n" + p_code + "};"
|
||||
@ -69,10 +99,12 @@ def parse_custom_language(file_content: str):
|
||||
return s
|
||||
|
||||
def handle_storage_label(m):
|
||||
l_docs = m.groups()[0].strip('\n')
|
||||
l_docs = m.groups()[0]
|
||||
l_name = m.groups()[1]
|
||||
l_allocs = m.groups()[2]
|
||||
storage_alloc = r"(?:\.(byte|res|dbyte|word|addr|faraddr|dword|ascii|asciiz)([, ]+(?:0x[a-fA-F0-9]+|0b[01]+|\d+|\w+|\"[^\n]*?[^\\\n]\")[ \n]*)*)"
|
||||
l_docs2 = m.groups()[3] # if doc was in the same line as the label
|
||||
|
||||
storage_alloc = r"\.(byte|res|dbyte|word|addr|faraddr|dword|asciiz?)(([, ]+(?:0x[a-fA-F0-9]+|0b[01]+|\d+|\w+|\"[^\n]*?[^\\\n]\")[ \n]*)*)"
|
||||
storage_alloc_arg = r"(0x[a-fA-F0-9]+|0b[01]+|\d+|\w+|\"[^\n]*[^\\\n]\")"
|
||||
|
||||
args = []
|
||||
@ -83,36 +115,42 @@ def parse_custom_language(file_content: str):
|
||||
if alloc_args:
|
||||
args += re.findall(storage_alloc_arg, alloc_args)
|
||||
|
||||
# pdebug(f"Storage label {l_name} with allocs '{[ma.group() for ma in allocs]}' and args '{args}'\n\t{m.groups()}")
|
||||
s = ""
|
||||
in_namespace = False
|
||||
# pdebug("ldocs for", l_name, l_docs)
|
||||
# pdebug(m.groups())
|
||||
# if the label is exported, put it in a namespace
|
||||
if l_name in exported_names:
|
||||
in_namespace = True
|
||||
namespace = exported_names[l_name]
|
||||
s += f"namespace {namespace}" + " {" + l_docs
|
||||
s += "\n"
|
||||
else:
|
||||
s += l_docs + "\n"
|
||||
s += f"namespace {namespace}" + " {"
|
||||
# docs after the namespace, otherwise they document the namespace
|
||||
if l_docs:
|
||||
s += l_docs
|
||||
# put the single line comment into a /** */ comment in front of the declaration
|
||||
if l_docs2:
|
||||
s += "/** "
|
||||
if not "brief" in l_docs2: s += "@brief "
|
||||
s += f"{l_docs2.strip(';')} */ "
|
||||
# completely ignoring the type of the storage allocation here
|
||||
if len(args) > 1:
|
||||
if all(arg.startswith("\"") for arg in args):
|
||||
s += f'char* {l_name} = "' + "".join(map(lambda x: x.strip('"'), args)) + '"'
|
||||
else:
|
||||
s += "bytes[] = {"
|
||||
s += f"bytes {l_name}[{len(args)}] = " + "{"
|
||||
for arg in args:
|
||||
s += arg + ","
|
||||
s += "}"
|
||||
s += s.strip(",") + "}"
|
||||
s = s.strip(",") + "}"
|
||||
else:
|
||||
# alloc_type label =
|
||||
l_type = allocs[0].groups()[0]
|
||||
if len(args) == 0:
|
||||
l_arg = None
|
||||
else:
|
||||
l_arg = args[0]
|
||||
# if res: use bytes[length] as type
|
||||
if l_type == "res":
|
||||
l_type = f"bytes[{l_arg}]"
|
||||
l_arg = None
|
||||
# else use type* as type
|
||||
else: l_type += "*"
|
||||
s += f"{l_type} {l_name}"
|
||||
if l_arg:
|
||||
@ -134,8 +172,9 @@ def parse_custom_language(file_content: str):
|
||||
r"^(Import(?:Zp)?) (\w+)((?: *, *\w+)+)": "",
|
||||
r"(?<!^;)\$([A-Fa-f0-9_]+)": r"0x\1", # $HEX -> 0xHEX except in comments
|
||||
r"(?<!^;)%([01_]+)": r"0b\1", # %BIN -> 0bBIN except in comments
|
||||
r"^((?:;;.*\n)*)^\.(proc|enum|macro) (\w+)(.*?)\n((?:.|\n)*?)\.end(proc|enum|macro).*": handle_procedure,
|
||||
r"^((?:;;.*\n)*) *(\w+):((?:\s*\.(?:byte|res|dbyte|word|addr|faraddr|dword|ascii|asciiz)(?:[, ]+(?:0x[a-fA-F0-9]+|0b[01]+|\d+|\w+|\"[^\n]*[^\\\n]\")[ \n]*)*)+)": handle_storage_label,
|
||||
r"^((?:;;.*\n)*) *\.(proc|enum|macro) (\w+)(.*?)\n((?:.|\n)*?)\.end(proc|enum|macro).*": handle_procedure,
|
||||
r"^((?:;;.*\n)*) *(\w+):((?:\s*\.(?:byte|res|dbyte|word|addr|faraddr|dword|asciiz?)(?:[, ]+(?:0x[a-fA-F0-9]+|0b[01]+|\d+|\w+|\"[^\n]*[^\\\n]\")[ \n]*)*)+)(;;.*)?": handle_storage_label,
|
||||
r"^INCLUDE_[A-Z0-9_]+ *= *1$": r"", # Include guard variables
|
||||
r";;": "//!", # C++ comments
|
||||
# TODO this is currently case sensitive
|
||||
r"(?<!^;)( *\w+ *= *[^;,\n]+?) *(//.*)?$": r"\1;\2", # semicolons after assignments, except in comments and when they already end with a comma or semicolon. Also preserve comments after the assignment
|
||||
@ -157,7 +196,6 @@ def parse_custom_language(file_content: str):
|
||||
for pat, subst in resub_patterns.items():
|
||||
file_content = re.sub(pat, subst, file_content, 0, re.MULTILINE)
|
||||
for pat,subst in patterns.items():
|
||||
pdebug(f"Now doing pattern: {pat}")
|
||||
(file_content, n_subst) = re.subn(pat, subst, file_content, 0, re.MULTILINE)
|
||||
return file_content
|
||||
|
||||
|
@ -3,6 +3,11 @@
|
||||
.include "keypad.h65"
|
||||
|
||||
.code
|
||||
|
||||
;;********************************************************************************
|
||||
;; @brief Print characters to the display when a button was pressed
|
||||
;; @ingroup applications
|
||||
;;********************************************************************************
|
||||
.proc keypad_printer
|
||||
jsr lcd::clear
|
||||
@printer_loop:
|
||||
|
@ -5,11 +5,13 @@
|
||||
.export print_slow
|
||||
|
||||
.code
|
||||
;********************************************************************************
|
||||
; @function Print a null-terminated string
|
||||
; @param ARG0-1: Address of the string to print
|
||||
; @param x: time to sleep in centiseconds
|
||||
;********************************************************************************
|
||||
;;********************************************************************************
|
||||
;; @function Print a null-terminated string with a delay between each character
|
||||
;; @param ARG0-1: Address of the string to print
|
||||
;; @param x: time to sleep in centiseconds
|
||||
;; @ingroup applications
|
||||
;; @clock_dependant
|
||||
;;********************************************************************************
|
||||
.proc print_slow
|
||||
ldy #$00
|
||||
@print_loop:
|
||||
|
@ -1,4 +1,5 @@
|
||||
.include "lcd.h65"
|
||||
.include "string.h65"
|
||||
.include "ps2_keyboard_text_handler.h65"
|
||||
|
||||
.export ps2_keyboard_printer
|
||||
@ -6,10 +7,36 @@
|
||||
.import home:absolute
|
||||
|
||||
.code
|
||||
|
||||
;;********************************************************************************
|
||||
;; @brief Print characters to the display when a key was pressed
|
||||
;; @details
|
||||
;; Print the character that corresponds to a key.
|
||||
;; This uses the @ref kb "text keyboard handler" to correctly handle modifier keys
|
||||
;;
|
||||
;; Controls:
|
||||
;; - `ESC`: Jump home
|
||||
;; - `Print`: Clear the display
|
||||
;; - `F12`: Restart the program
|
||||
;; @ingroup applications keyboard
|
||||
;;********************************************************************************
|
||||
.proc ps2_keyboard_printer
|
||||
jsr lcd::clear
|
||||
jsr kb::init
|
||||
jeq loop
|
||||
ps2kb_PrintCmdFailed
|
||||
; jmp homeloop
|
||||
ps2kb_CmdEnable
|
||||
jsr ps2kb::begin_receive
|
||||
|
||||
loop:
|
||||
wai
|
||||
; ; put shift, ralt and lalt in debug leds
|
||||
; lda kb::modifier
|
||||
; Reverse A
|
||||
; and #%00000111
|
||||
; ora IO1 + IO::RANH
|
||||
; sta IO1 + IO::RANH
|
||||
lda kb::char
|
||||
beq @no_char
|
||||
stz kb::char
|
||||
@ -18,11 +45,13 @@ loop:
|
||||
@no_char:
|
||||
lda kb::keycode
|
||||
beq loop
|
||||
|
||||
stz kb::keycode
|
||||
cmp #kb::K::ESCAPE
|
||||
beq @esacpe
|
||||
cmp #kb::K::PRINT
|
||||
beq @clear_display
|
||||
cmp #kb::K::F12
|
||||
jeq ps2_keyboard_printer
|
||||
bra loop
|
||||
@esacpe:
|
||||
jmp home
|
||||
@ -30,4 +59,3 @@ loop:
|
||||
jsr lcd::clear
|
||||
bra loop
|
||||
.endproc
|
||||
|
||||
|
@ -5,15 +5,15 @@ ExportZp kb, modifier
|
||||
|
||||
.zeropage
|
||||
;; @ref kb::MOD "status of the modifier keys"
|
||||
modifier: .byte
|
||||
modifier: .res 1
|
||||
.bss
|
||||
;; previous scancode is used to determine if a key was released (BREAK sent previously)
|
||||
;; will be $ff if the previous scancode was K_BREAK
|
||||
previous_scancode: .byte
|
||||
previous_scancode: .res 1
|
||||
;; 0 when no key or non-character key was pressed, otherwise character of the key (with modifiers applied)
|
||||
char: .byte
|
||||
char: .res 1
|
||||
;; @ref kb::K "keycode" of the last key that was pressed or 0 if none was pressed
|
||||
keycode: .byte
|
||||
keycode: .res 1
|
||||
|
||||
.code
|
||||
;;********************************************************************************
|
||||
|
@ -10,6 +10,29 @@
|
||||
.import home:absolute
|
||||
|
||||
.code
|
||||
|
||||
;;********************************************************************************
|
||||
;; @brief Send various commands to the keyboard and print the response bytes
|
||||
;; @details
|
||||
;; - `0`: `0xf0` query scancode set
|
||||
;; - `1`: `0xee` echo
|
||||
;; - `2`: `0xf2` identify
|
||||
;; - `3`: `0xf3` set typematic min speed and delay (`0b0111111`)
|
||||
;; - `4`: `0xf4` enable
|
||||
;; - `5`: `0xf5` disable
|
||||
;; - `6`: `0xf3` set typematic max speed and min delay (`0b00000000`)
|
||||
;; - `7`: `0xf7` set typematic all
|
||||
;; - `8`: `0xf8` set make/release all
|
||||
;; - `9`: `0xed` set CAPSLOCK led
|
||||
;; - `#`: `0xed` set SCROLLLOCK led
|
||||
;; - `C`: `0xed` set NUMLOCK led
|
||||
;; - `D`: `0xed` turn all leds off
|
||||
;; - `A`: reprint menu
|
||||
;; - `B`: reprint menu
|
||||
;; - `*`: jump home
|
||||
;; For more details, see https://wiki.osdev.org/PS/2_Keyboard
|
||||
;; @ingroup applications keyboard
|
||||
;;********************************************************************************
|
||||
.proc ps2_keyboard_util
|
||||
stz kp::_DEBUG_VAL
|
||||
jsr skb::init
|
||||
@ -67,6 +90,7 @@ loop:
|
||||
beq @lD
|
||||
jsr lcd::print_char
|
||||
jmp loop
|
||||
|
||||
@l0: ; get scancode set
|
||||
lda #$f0
|
||||
ldx #0
|
||||
@ -99,7 +123,7 @@ loop:
|
||||
@l8: ; set make/release all
|
||||
lda #$f8
|
||||
bra @send_cmd
|
||||
@l9: ; set CAPSLOCK
|
||||
@l9: ; set CAPSLOCK led
|
||||
lda #$ed
|
||||
ldx #kb::MOD::CAPSLOCK
|
||||
bra @send_cmd
|
||||
|
@ -3,14 +3,16 @@
|
||||
.export sleep
|
||||
|
||||
.code
|
||||
;********************************************************************************
|
||||
; @function sleep
|
||||
; @param x: Time to sleep in centiseconds (10^-2s = 10ms)
|
||||
; @details
|
||||
; Interrupts might change the actual time to finish
|
||||
; To be exact, time_cs is in units of 0.010244s
|
||||
; @modifies: ARG15
|
||||
;********************************************************************************
|
||||
;;********************************************************************************
|
||||
;; @function sleep
|
||||
;; @param x: Time to sleep in centiseconds (10^-2s = 10ms) @ 1MHz
|
||||
;; @details
|
||||
;; Interrupts might change the actual time to finish
|
||||
;; To be exact, time_cs is in units of 0.010244s
|
||||
;; @modifies: ARG15
|
||||
;; @ingroup applications
|
||||
;; @clock_dependant
|
||||
;;********************************************************************************
|
||||
.proc sleep
|
||||
_VAR_1 = ARG15
|
||||
stz _VAR_1
|
||||
|
@ -1,3 +1,6 @@
|
||||
;;********************************************************************************
|
||||
;; @module VIU - VI Unimproved
|
||||
;;********************************************************************************
|
||||
.include "lcd.h65"
|
||||
.include "ps2_keyboard_text_handler.h65"
|
||||
|
||||
@ -13,7 +16,6 @@ buffer: .res 256
|
||||
stz ptr
|
||||
stz ptr+1
|
||||
stz buffer
|
||||
|
||||
.endproc
|
||||
|
||||
.proc insert_mode
|
||||
|
20
readme.md
20
readme.md
@ -5,12 +5,18 @@ The assembler used for this project is the excellent [ca65](https://github.com/c
|
||||
After assembling it, the binary is loaded onto the EEPROM using [my *eeprom.py* script](https://git.quintern.xyz/MatthiasQuintern/AT28C256-rpi-util) on a Raspberry Pi 4B.
|
||||
|
||||
## Operating System
|
||||
... is probably a far stretch, since it is just the programs I wrote pieced together. My "os" consists of these functionalities:
|
||||
- Main Menu:
|
||||
- Printer: Prints the characters you press on the keypad to the lcd.
|
||||
- Temperature: Shows the temperature using a dht sensor. *Work in progress, this does not work yet*
|
||||
- Text 1: Show a 4x16 character text (defined at compile time)
|
||||
- Text 2: Show a 4x16 character text (defined at compile time)
|
||||
- Ringbuffer for pressed keys.
|
||||
... is probably a far stretch, since it is just the programs I wrote pieced together. My "OS" consists of these functionalities:
|
||||
- Supported Hardware:
|
||||
- 4x4 Matrix Keypad
|
||||
- 4x16 Characters LCD Display
|
||||
- PS/2 Keyboard
|
||||
- SPI Connection to an Arduino
|
||||
- Software
|
||||
- Keyboard and keypad printer: Prints the characters you press on to the lcd
|
||||
<!-- - Temperature: Shows the temperature using a dht sensor. *Work in progress, this does not work yet* -->
|
||||
- (Stylishly) print formated strings to the LCD
|
||||
- Sleep
|
||||
- Send various commands to the keyboard
|
||||
- Ringbuffer
|
||||
|
||||
> It's not much, but it's honest work.
|
||||
|
42
spicode.s65
42
spicode.s65
@ -79,7 +79,7 @@ CODE_START:
|
||||
@l0:
|
||||
jmp ps2_keyboard_util
|
||||
@l1:
|
||||
jmp _ps2_keyboard_printer
|
||||
jmp ps2_keyboard_printer
|
||||
@l2:
|
||||
lcd_SetCursorPos $26
|
||||
lda #'6'
|
||||
@ -101,46 +101,6 @@ CODE_START:
|
||||
@lD:
|
||||
jmp @loop
|
||||
|
||||
.proc _ps2_keyboard_printer
|
||||
jsr lcd::clear
|
||||
jsr kb::init
|
||||
jeq loop
|
||||
ps2kb_PrintCmdFailed
|
||||
; jmp homeloop
|
||||
ps2kb_CmdEnable
|
||||
jsr ps2kb::begin_receive
|
||||
|
||||
|
||||
loop:
|
||||
wai
|
||||
; put shift, ralt and lalt in debug leds
|
||||
lda kb::modifier
|
||||
Reverse A
|
||||
and #%00000111
|
||||
ora IO1 + IO::RANH
|
||||
sta IO1 + IO::RANH
|
||||
lda kb::char
|
||||
beq @no_char
|
||||
stz kb::char
|
||||
jsr lcd::print_char
|
||||
bra loop
|
||||
@no_char:
|
||||
lda kb::keycode
|
||||
beq loop
|
||||
stz kb::keycode
|
||||
cmp #kb::K::ESCAPE
|
||||
beq @esacpe
|
||||
cmp #kb::K::PRINT
|
||||
beq @clear_display
|
||||
cmp #kb::K::F12
|
||||
jeq _ps2_keyboard_printer
|
||||
bra loop
|
||||
@esacpe:
|
||||
jmp home
|
||||
@clear_display:
|
||||
jsr lcd::clear
|
||||
bra loop
|
||||
.endproc
|
||||
|
||||
|
||||
|
||||
|
@ -8,28 +8,43 @@
|
||||
.ifndef INCLUDE_IOW65C22
|
||||
INCLUDE_IOW65C22 = 1
|
||||
|
||||
;;********************************************************************************
|
||||
;; @brief Versatile Interface Adapter (VIA) W65C22
|
||||
;; @ingroup utility
|
||||
;; @device Western Design - W65C22N Versatile Interface Adapter
|
||||
;; @todo rename to VIA
|
||||
;; @warning @anchor via_hardware_bug
|
||||
;; The 6522 and 65C22 have a hardware bug, where a bit is not read in when the
|
||||
;; external shift register clock transitions close to @f$ \phi_2 @f$.
|
||||
;; To resolve this, you should use a @f$ \phi_2 @f$ controlled flip flop to ensure
|
||||
;; the external clock transitions after the system clock.
|
||||
;;********************************************************************************
|
||||
.scope IO
|
||||
|
||||
; not using a struct for this since the syntax for access would be the same,
|
||||
; ie label+IO::RA
|
||||
;;********************************************************************************
|
||||
;; @brief VIA register offsets from the base address
|
||||
;; @details
|
||||
;; Use like this: `VIA_ADDRESS + IO::RB`
|
||||
;;********************************************************************************
|
||||
.enum
|
||||
; IO-CHIPS OFFSETS FOR PINS FROM BASE ADDRESS
|
||||
RB = $0 ; Register B (ORB/IRB)
|
||||
RA = $1 ; Register A (ORA/IRA)
|
||||
DDRB = $2 ; Data Direction Register B
|
||||
DDRA = $3 ; Data Direction Register A
|
||||
T1CL = $4 ; Timer 1 Counter Low/High
|
||||
RB = $0 ;; Register B (ORB/IRB)
|
||||
RA = $1 ;; Register A (ORA/IRA)
|
||||
DDRB = $2 ;; Data Direction Register B
|
||||
DDRA = $3 ;; Data Direction Register A
|
||||
T1CL = $4 ;; Timer 1 Counter Low/High
|
||||
T1CH = $5
|
||||
T1LL = $6 ; Timer 1 Latch Low/High
|
||||
T1LL = $6 ;; Timer 1 Latch Low/High
|
||||
T1LH = $7
|
||||
T2CL = $8 ; Timer 2 Counter Low/High
|
||||
T2CL = $8 ;; Timer 2 Counter Low/High
|
||||
T2CH = $9
|
||||
SR = $a ; Shift Register
|
||||
ACR = $b ; Auxiliary Control Register
|
||||
PCR = $c ; Peripheral Control Register
|
||||
IFR = $d ; Interrupt Flag Register
|
||||
IER = $e ; Interrupt Enable Register
|
||||
RANH = $f ; RA without handshake
|
||||
SR = $a ;; Shift Register
|
||||
ACR = $b ;; Auxiliary Control Register
|
||||
PCR = $c ;; Peripheral Control Register
|
||||
IFR = $d ;; Interrupt Flag Register
|
||||
IER = $e ;; Interrupt Enable Register
|
||||
RANH = $f ;; RA without handshake
|
||||
.endenum
|
||||
|
||||
.enum ACR_MASK ; ACR Masks
|
||||
@ -40,27 +55,32 @@ INCLUDE_IOW65C22 = 1
|
||||
T1 = %11000000
|
||||
.endenum
|
||||
|
||||
.enum ACR ; ACR Settings
|
||||
;;********************************************************************************
|
||||
;; @brief Settings for Auxiliary Control Register
|
||||
;; @details
|
||||
;; `OR` the values with the appropriate IO::ACR_MASK to not target only specific settings
|
||||
;;********************************************************************************
|
||||
.enum ACR
|
||||
; SR Modes
|
||||
SR_DISABLE = %00000000 ; Disabled
|
||||
SR_SIN_T2 = %00000100 ; Shift in under control of T2
|
||||
SR_SIN_PHI2 = %00001000 ; Shift in under control of PHI2
|
||||
SR_SIN_PHIE = %00001100 ; Shift in under control of external clock
|
||||
SR_SOUT_FREE_T2 = %00010000 ; Shift out free running at T2 rate
|
||||
SR_SOUT_T2 = %00010100 ; Shift out under control of T2
|
||||
SR_SOUT_PHI2 = %00011000 ; Shift out under control of PHI2
|
||||
SR_SOUT_PHIE = %00011100 ; Shift out under control of external clock
|
||||
SR_DISABLE = %00000000 ;; Disabled
|
||||
SR_SIN_T2 = %00000100 ;; Shift in under control of T2
|
||||
SR_SIN_PHI2 = %00001000 ;; Shift in under control of PHI2
|
||||
SR_SIN_PHIE = %00001100 ;; Shift in under control of external clock
|
||||
SR_SOUT_FREE_T2 = %00010000 ;; Shift out free running at T2 rate
|
||||
SR_SOUT_T2 = %00010100 ;; Shift out under control of T2
|
||||
SR_SOUT_PHI2 = %00011000 ;; Shift out under control of PHI2
|
||||
SR_SOUT_PHIE = %00011100 ;; Shift out under control of external clock
|
||||
; T1 Modes
|
||||
T1_IRQ_LOAD = %00000000 ; Timed interrupt each time T1 is loaded
|
||||
T1_IRQ_CONT = %01000000 ; Continuous interrupts
|
||||
T1_IRQ_LOAD_PB7 = %10000000 ; Timed interrupt each time T1 is loaded - PB7 One Shot output
|
||||
T1_IRQ_CONT_PB7 = %11000000 ; Continuous interrupts - PB7 Square wave output
|
||||
T1_IRQ_LOAD = %00000000 ;; Timed interrupt each time T1 is loaded
|
||||
T1_IRQ_CONT = %01000000 ;; Continuous interrupts
|
||||
T1_IRQ_LOAD_PB7 = %10000000 ;; Timed interrupt each time T1 is loaded - PB7 One Shot output
|
||||
T1_IRQ_CONT_PB7 = %11000000 ;; Continuous interrupts - PB7 Square wave output
|
||||
; T2 Modes
|
||||
T2_IRQ_LOAD = %00000000 ; Timed interrupt each time T2 is loaded
|
||||
T2_COUNT_PB6 = %00100000 ; Count down with pulsen on PB6
|
||||
T2_IRQ_LOAD = %00000000 ;; Timed interrupt each time T2 is loaded
|
||||
T2_COUNT_PB6 = %00100000 ;; Count down with pulsen on PB6
|
||||
; Latch
|
||||
LATCH_DISABLE = %00000000
|
||||
LATCH_ENBLE = %00000000
|
||||
LATCH_DISABLE = %00000000 ;; `OR` this with IO::ACR_MASK::PA or IO::ACR_MASK::PB
|
||||
LATCH_ENBLE = %00000011 ;; `OR` this with IO::ACR_MASK::PA or IO::ACR_MASK::PB
|
||||
.endenum
|
||||
|
||||
.enum PCR_MASK ; PCR Masks
|
||||
@ -70,6 +90,11 @@ INCLUDE_IOW65C22 = 1
|
||||
CB2 = %11100000 ;
|
||||
.endenum
|
||||
|
||||
;;********************************************************************************
|
||||
;; @brief Settings for Peripheral Control Register
|
||||
;; @details
|
||||
;; `OR` the values with the appropriate IO::PCR_MASK to not target only specific settings
|
||||
;;********************************************************************************
|
||||
.enum PCR
|
||||
; CA1 Modes
|
||||
CA1_IN_AE = %00000000 ; Input-negative active edge
|
||||
@ -97,7 +122,10 @@ INCLUDE_IOW65C22 = 1
|
||||
CB2_OUT_HIGH = %11100000 ; High output
|
||||
.endenum
|
||||
|
||||
; IFR/IER bits
|
||||
|
||||
;;********************************************************************************
|
||||
;; @brief Interrupt Flag/Enable Register bits
|
||||
;;********************************************************************************
|
||||
.enum IRQ
|
||||
CA2 = %00000001
|
||||
CA1 = %00000010
|
||||
@ -112,7 +140,7 @@ INCLUDE_IOW65C22 = 1
|
||||
;;********************************************************************************
|
||||
;; @macro Enable an interrupt source
|
||||
;; @modifies: A
|
||||
;; @param flag: A flag of the interrupt flag register (IO:IRQ)
|
||||
;; @param flag: A flag of the interrupt flag register (IO::IRQ)
|
||||
;;********************************************************************************
|
||||
.macro IO_EnableIRQ ioaddr, flag
|
||||
lda #(IO::IRQ::IRQ | flag)
|
||||
@ -121,7 +149,7 @@ INCLUDE_IOW65C22 = 1
|
||||
;;********************************************************************************
|
||||
;; @macro Disable an interrupt source
|
||||
;; @modifies: A
|
||||
;; @param flag: A flag of the interrupt flag register (IO:IRQ)
|
||||
;; @param flag: A flag of the interrupt flag register (IO::IRQ)
|
||||
;;********************************************************************************
|
||||
.macro IO_DisableIRQ ioaddr, flag
|
||||
lda #flag
|
||||
|
@ -1,17 +1,20 @@
|
||||
;********************************************************************************
|
||||
; @module keypad4x4
|
||||
; @type driver
|
||||
; @device 4x4 Matrix Keypad
|
||||
; @details
|
||||
; The LCD must be connected to a W65C22N Interface Chip:
|
||||
; - IO.RA0-7 ->
|
||||
; @requires KP_IO: Base Address of IO Chip
|
||||
; @depends IO-W65C22N
|
||||
;********************************************************************************
|
||||
;;********************************************************************************
|
||||
;; @module keypad4x4
|
||||
;; @type driver
|
||||
;; @device 4x4 Matrix Keypad
|
||||
;; @details
|
||||
;; The LCD must be connected to a W65C22N Interface Chip:
|
||||
;; - IO.RA0-7 ->
|
||||
;; @requires KP_IO: Base Address of IO Chip
|
||||
;; @depends IO-W65C22N
|
||||
;;********************************************************************************
|
||||
.ifndef INCLUDE_KEYPAD
|
||||
INCLUDE_KEYPAD = 1
|
||||
.include "system.h65"
|
||||
|
||||
;;********************************************************************************
|
||||
;; @brief 4x4 Matrix Keypad
|
||||
;;********************************************************************************
|
||||
.scope kp
|
||||
KP_IO = IO2
|
||||
; .import KP_IO
|
||||
|
@ -1,6 +1,6 @@
|
||||
;;********************************************************************************
|
||||
;; @module LCD-W164B
|
||||
;; @type driver
|
||||
;; @ingroup driver
|
||||
;; @device ELECTRONIC ASSEMBLY - W164B-NLW
|
||||
;; @details
|
||||
;; The LCD must be connected to a W65C22N Interface Chip:
|
||||
@ -8,7 +8,6 @@
|
||||
;; - IO.RA5 -> LCD.RS register select
|
||||
;; - IO.RA6 -> LCD.R/W read/write
|
||||
;; - IO.RA7 -> LCD.E enable
|
||||
;;
|
||||
;; @requires IO: Base Address of IO Chip
|
||||
;; @depends IO-W65C22N
|
||||
;;********************************************************************************
|
||||
@ -19,6 +18,7 @@ INCLUDE_LCD = 1
|
||||
|
||||
;;********************************************************************************
|
||||
;; @brief LCD character display
|
||||
;; @ingroup driver
|
||||
;;********************************************************************************
|
||||
.scope lcd
|
||||
LCD_IO = IO1
|
||||
|
@ -11,7 +11,7 @@ Export lcd,_charcount
|
||||
.bss
|
||||
_charcount: .res 1
|
||||
|
||||
; TODO when clockspeeds are more than 1MHz, _cmd, _write_ram and _read_ram might need to be adjusted
|
||||
; @TODO when clockspeeds are more than 1MHz, _cmd, _write_ram and _read_ram might need to be adjusted
|
||||
.code
|
||||
;;********************************************************************************
|
||||
;; @function Initialize the lcd module
|
||||
|
@ -1,6 +1,6 @@
|
||||
;;********************************************************************************
|
||||
;; @module ps2_keyboard
|
||||
;; @type driver
|
||||
;; @ingroup drivers
|
||||
;; @details:
|
||||
;; Support for a PS2 Keyboard using the shift register of a 6522 VIA
|
||||
;; @section reading Reading a scancode/command answer
|
||||
@ -17,32 +17,52 @@
|
||||
;; The scancode may be processed by storing the address of a handler subroutine in
|
||||
;; `ps2kb::scancode_handler`. This handler can load the scancode byte from `ps2kb::scancode`.
|
||||
;;
|
||||
;;
|
||||
;; To use a different layout, change the enum K and the CHARS_NOMOD and CHARS_MODSHIFT
|
||||
;; @warning
|
||||
;; The value with which the timer is loaded must depends on the clock frequency
|
||||
;; of the keyboard and the computer
|
||||
;;
|
||||
;;********************************************************************************
|
||||
.ifndef INCLUDE_PS2_KEYBOARD
|
||||
INCLUDE_PS2_KEYBOARD = 1
|
||||
.include "system.h65"
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @brief PS/2 Keyboard
|
||||
;; This requires the data line to be hooked up to `CB2` and the clock to `CB1`.
|
||||
;; The VIA will be set to shift in the data into the shift register under the external clock.
|
||||
;; @see @ref via_hardware_bug "VIA external clock bug"
|
||||
;; @include keyboard
|
||||
;; @ingroup drivers
|
||||
;;********************************************************************************
|
||||
.scope ps2kb
|
||||
Import ps2kb, init, begin_receive, scancode, status, scancode_handler
|
||||
Import ps2kb, _receive_irq_shift_reg_handler, _receive_irq_timer_handler, _send_byte, _send_irq_shift_reg_handler, _send_irq_timer_handler,
|
||||
Import ps2kb, send_command, send_cmd, send_data, cmd_response, response_length, FMT_CMD_FAIL
|
||||
|
||||
;; Base address of the VIA the keyboard is conencted to
|
||||
VIA = IO1
|
||||
; Enough time must pass for 3 bits to be shifted in.
|
||||
; TIMER_RECV = 230 ; 230 ms (@1MHz)
|
||||
TIMER_RECV = 400 ; 230 ms (@1MHz)
|
||||
; Enough time must pass for one bit must be shifted out (parity),
|
||||
; but at most two (parity+stop).
|
||||
; After that, the interrupt must have happened because the keyboard will pull data low.
|
||||
; At that point, the SR needs to be set to input again
|
||||
; TIMER_SEND = 230 ; 180 ms (@1MHz)
|
||||
TIMER_SEND = 400 ; 180 ms (@1MHz)
|
||||
|
||||
;; @brief #clock cycles to to wait for the last 3 bits after the first 8 have been shifted in
|
||||
;; @details
|
||||
;; The last 3 bits take about 230 ms.
|
||||
;; Calculate the appropriate value using: @f$ N_\text{cycles} = 230 \times f_\text{in MHZ} @f$
|
||||
;; - 230 \@ 1MHz
|
||||
;; - 400 \@ 1.84 MHz
|
||||
;; @clock_dependant
|
||||
TIMER_RECV = 400
|
||||
;; @brief #clock cycles to wait after loading the SR a second time while sending a command to the keyboard
|
||||
;; @details
|
||||
;; Enough time must pass for one bit must be shifted out (parity),
|
||||
;; but at most two (parity+stop).
|
||||
;; After that, the interrupt must have happened because the keyboard will pull data low.
|
||||
;; At that point, the shift register needs to be set to input again
|
||||
;;
|
||||
;; Values that seem to work:
|
||||
;; - 230 \@ 1MHz
|
||||
;; - 400 \@ 1.84 MHz
|
||||
;; @clock_dependant
|
||||
TIMER_SEND = 400
|
||||
|
||||
PULL_REG = IO::RANH
|
||||
PULL_DDR = IO::DDRA
|
||||
@ -50,24 +70,24 @@ PULL_DDR = IO::DDRA
|
||||
PULL_MASK_CLK = %00010000
|
||||
|
||||
; using ff because 0 is a possible data byte (set led)
|
||||
NO_DATA = $ff ; indicates that no data byte should be send
|
||||
NO_RESPONSE = $ff ; indicates a command did not receive a response (yet)
|
||||
ACK = $fa ; successful transmission
|
||||
RESEND = $fe ; unsuccessful transmission
|
||||
NO_DATA = $ff ;; indicates that no data byte should be send
|
||||
NO_RESPONSE = $ff ;; indicates a command did not receive a response (yet)
|
||||
ACK = $fa ;; successful transmission
|
||||
RESEND = $fe ;; unsuccessful transmission
|
||||
|
||||
|
||||
.enum STATUS
|
||||
RECEIVE_KEYS = %10000000 ; keyboard sends scancodes
|
||||
RECEIVE_ANSWER = %01000000 ; keyboard replies to a command
|
||||
SEND_CMD = %00100000 ; host sends/sent the command byte
|
||||
SEND_DATA = %00010000 ; host sends/sent the data byte
|
||||
SEND_RECV = %00001000 ; keyboard sends additional data byte
|
||||
SEND = SEND_CMD | SEND_DATA | SEND_RECV ; host is sending something, only used for checking status
|
||||
RECEIVE_KEYS = %10000000 ;; keyboard sends scancodes
|
||||
RECEIVE_ANSWER = %01000000 ;; keyboard replies to a command
|
||||
SEND_CMD = %00100000 ;; host sends/sent the command byte
|
||||
SEND_DATA = %00010000 ;; host sends/sent the data byte
|
||||
SEND_RECV = %00001000 ;; keyboard sends additional data byte
|
||||
SEND = SEND_CMD | SEND_DATA | SEND_RECV ;; host is sending something, only used for checking status
|
||||
NONE = %00000000
|
||||
.endenum
|
||||
|
||||
.enum TYPEMATIC
|
||||
REPEAT_MASK = %00011111 ; 00000 = 30Hz, ..., 11111 = 2Hz
|
||||
REPEAT_MASK = %00011111 ;; 00000 = 30Hz, ..., 11111 = 2Hz
|
||||
DELAY250 = %00000000
|
||||
DELAY500 = %00100000
|
||||
DELAY750 = %01000000
|
||||
@ -186,6 +206,10 @@ RESEND = $fe ; unsuccessful transmission
|
||||
bne :-
|
||||
.endmacro
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @note You need to manually include `string.h65` when using this macro!
|
||||
;;********************************************************************************
|
||||
.macro ps2kb_PrintCmdFailed
|
||||
Printf ps2kb::FMT_CMD_FAIL,ps2kb::send_cmd,ps2kb::send_data,ps2kb::cmd_response,ps2kb::cmd_response+1,ps2kb::cmd_response+2
|
||||
.endmacro
|
||||
|
@ -7,20 +7,21 @@ Export ps2kb, _receive_irq_shift_reg_handler, _receive_irq_timer_handler, _send_
|
||||
Export ps2kb, send_command, send_cmd, send_data, cmd_response, response_length, FMT_CMD_FAIL
|
||||
|
||||
.bss
|
||||
status: .res 1 ; current status
|
||||
prev_status: .res 1 ; status before sending command
|
||||
send_last_bits: .res 1 ; last bits to load after 8 bits were shifted out
|
||||
send_cmd: .res 1 ; command to send/last sent
|
||||
send_data: .res 1 ; data byte to send/last sent or NO_DATA
|
||||
expect_data_length: .res 1 ; number of data bytes to expect from keyboard
|
||||
response_length: .res 1 ; number of response bytes from keyboard
|
||||
cmd_response: .res 3 ; responses from keyboard
|
||||
key_read: .res 2 ; first 8 bits, last 3 bits from scancode
|
||||
scancode: .res 1 ; last received scancode
|
||||
scancode_handler: .res 2 ; pointer to a function that handles new scancodes
|
||||
status: .res 1 ;; current status
|
||||
prev_status: .res 1 ;; status before sending command
|
||||
send_last_bits: .res 1 ;; last bits to load after 8 bits were shifted out
|
||||
send_cmd: .res 1 ;; command to send/last sent
|
||||
send_data: .res 1 ;; data byte to send/last sent or NO_DATA
|
||||
expect_data_length: .res 1 ;; number of data bytes to expect from keyboard
|
||||
response_length: .res 1 ;; number of response bytes from keyboard
|
||||
cmd_response: .res 3 ;; responses from keyboard
|
||||
key_read: .res 2 ;; first 8 bits, last 3 bits from scancode
|
||||
scancode: .res 1 ;; last received scancode
|
||||
scancode_handler: .res 2 ;; pointer to a function that handles new scancodes
|
||||
|
||||
.code
|
||||
|
||||
; spi-transferred code will be placed here
|
||||
; these are macros and not subroutines to save time during the interrupt handler (no jsr, rts)
|
||||
;;********************************************************************************
|
||||
;; @macro Enable the clock signal from the keyboard
|
||||
@ -80,6 +81,15 @@ scancode_handler: .res 2 ; pointer to a function that handles new scancod
|
||||
.endmacro
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @function Initialize the keyboard
|
||||
;; @details
|
||||
;; - @ref _DisableClock "Disable the clock"
|
||||
;; - Initialize variables to 0
|
||||
;; - Clear the VIAs shift register and set T2 to oneshote mode
|
||||
;; - Set scancode_handler to immediately return (dont handle scancodes)
|
||||
;; @modifies: A
|
||||
;;********************************************************************************
|
||||
.proc init
|
||||
_DisableClock
|
||||
stz key_read
|
||||
@ -468,5 +478,5 @@ scancode_handler: .res 2 ; pointer to a function that handles new scancod
|
||||
.endproc
|
||||
|
||||
.rodata
|
||||
;; Can be used by other programs
|
||||
;; Format string that can be used by other programs for keyboard command errors
|
||||
FMT_CMD_FAIL: .asciiz "PS/2 Cmd fail: %x-%x > %x%x%x "
|
||||
|
@ -1,6 +1,5 @@
|
||||
;;********************************************************************************
|
||||
;; @module SPI-P
|
||||
;; @type driver
|
||||
;; @details
|
||||
;; Support being a peripheral SPI device.
|
||||
;; @depends IO-W65C22N
|
||||
@ -11,11 +10,16 @@ INCLUDE_SPI = 1
|
||||
.include "system/system.h65"
|
||||
|
||||
;;********************************************************************************
|
||||
;; @brief SPI-Peripheral
|
||||
;; @brief Support being a peripheral SPI device
|
||||
;; @details
|
||||
;; This requires the data line to be hooked up to `CB2` and the clock to `CB1`.
|
||||
;; The VIA will be set to shift in the data into the shift register under the external clock.
|
||||
;; @ingroup driver
|
||||
;; @see via_hardware_bug "VIA external clock bug"
|
||||
;;********************************************************************************
|
||||
.scope spi_p
|
||||
|
||||
|
||||
;; Address of the VIA that is used for the spi connection
|
||||
SPI_IO = IO2
|
||||
Import spi_p, init, irq_handler, status, buffer_size, recv_size
|
||||
ImportZp spi_p, buffer_ptr
|
||||
|
22
test.s65
22
test.s65
@ -1,22 +0,0 @@
|
||||
; .include "other/file.h65"
|
||||
|
||||
|
||||
.segment "TEST"
|
||||
; .proc my_subroutine
|
||||
; pha
|
||||
; bbr4 var1,@bit_4_set
|
||||
; bit var1
|
||||
; ; macro packs are supported
|
||||
; jmi other_routine
|
||||
; lda #'a'
|
||||
; sta char
|
||||
; bra @end
|
||||
; @bit_4_set:
|
||||
; ; custom macros can be highlighted
|
||||
; Printf STR_FMT,char,var1
|
||||
; @end:
|
||||
; pla
|
||||
; rts
|
||||
; .endproc
|
||||
|
||||
; STR_FMT: .asciiz "%c: num=%x"
|
@ -1,19 +1,22 @@
|
||||
;********************************************************************************
|
||||
; @module math
|
||||
; @type utility
|
||||
; @details
|
||||
; Math library
|
||||
;********************************************************************************
|
||||
;;********************************************************************************
|
||||
;; @module math
|
||||
;; @details
|
||||
;; Math library
|
||||
;;********************************************************************************
|
||||
.ifndef INCLUDE_MATH
|
||||
INCLUDE_MATH = 1
|
||||
|
||||
;;********************************************************************************
|
||||
;; @brief Math library
|
||||
;; @ingroup utility
|
||||
;;********************************************************************************
|
||||
.scope math
|
||||
|
||||
;********************************************************************************
|
||||
; @macro Divide a num (or A) by a factor
|
||||
; @param num: Memory or A
|
||||
; @param divider: must be power of 2
|
||||
;********************************************************************************
|
||||
;;********************************************************************************
|
||||
;; @macro Divide a num (or A) by a factor
|
||||
;; @param num: Memory or A
|
||||
;; @param divider: must be power of 2
|
||||
;;********************************************************************************
|
||||
.macro div num,divider
|
||||
.if divider = 2
|
||||
lsr num
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
.rodata
|
||||
.align 256
|
||||
;;********************************************************************************
|
||||
;; @brief A 256 byte table where the *i*-th byte is the value *i* with bits reversed
|
||||
;; @see Reverse
|
||||
;;********************************************************************************
|
||||
REVERSE_TABLE:
|
||||
.byte $00, $80, $40, $c0, $20, $a0, $60, $e0
|
||||
.byte $10, $90, $50, $d0, $30, $b0, $70, $f0
|
||||
|
@ -1,8 +1,8 @@
|
||||
;;********************************************************************************
|
||||
;; @module string
|
||||
;; @type utility
|
||||
;; @details
|
||||
;; String utility
|
||||
;; @see str
|
||||
;;********************************************************************************
|
||||
.ifndef INCLUDE_STRING
|
||||
INCLUDE_STRING = 1
|
||||
@ -12,6 +12,7 @@ INCLUDE_STRING = 1
|
||||
|
||||
;;********************************************************************************
|
||||
;; @brief String utility
|
||||
;; @ingroup utility
|
||||
;;********************************************************************************
|
||||
.scope str
|
||||
Import str, strf, printf_buffer
|
||||
@ -22,7 +23,7 @@ Import str, uint8_to_hex_str, uint_to_hex_str
|
||||
;;********************************************************************************
|
||||
;; @macro Helper for str::Strf macro
|
||||
;; @details
|
||||
;; Store arg in ARG4-ARG... and increment counter variable @N_ARGS one.
|
||||
;; Store arg in ARG4-ARG... and increment counter variable `\@N_ARGS` by one.
|
||||
;; Arg can be x, y, immediate or an address
|
||||
;;********************************************************************************
|
||||
.macro _StrfStoreArg arg
|
||||
|
@ -2,6 +2,10 @@
|
||||
Export str, strf, printf_buffer
|
||||
|
||||
.bss
|
||||
;;********************************************************************************
|
||||
;; @brief Used to store output string of Printf macro
|
||||
;; @todo Use dynamically allocated buffer when a memory allocator is implemented
|
||||
;;********************************************************************************
|
||||
printf_buffer: .res $41
|
||||
|
||||
.zeropage
|
||||
@ -14,14 +18,15 @@ digits: .res 1
|
||||
;;********************************************************************************
|
||||
;; @function Format a string
|
||||
;; @details
|
||||
;; If there is no value to be read, the Pz will be set
|
||||
;; If there is no value to be read, the `Pz` will be set
|
||||
;; Formats:
|
||||
;; - x: unsigned hex integer (1 byte) -> 2 chars
|
||||
;; - X: unsigned hex integer (2 byte) -> 4 chars TODO
|
||||
;; - u: unsigned decimal integer (1 byte) TODO
|
||||
;; - U: unsigned decimal integer (2 bytes) TODO
|
||||
;; - s: null-terminated string (2 bytes ptr)
|
||||
;; - c: char
|
||||
;; - `x`: unsigned hex integer (1 byte) -> 2 chars
|
||||
;; - `X`: unsigned hex integer (2 byte) -> 4 chars TODO
|
||||
;; - `u`: unsigned decimal integer (1 byte) TODO
|
||||
;; - `U`: unsigned decimal integer (2 bytes) TODO
|
||||
;; - `s`: null-terminated string (2 bytes ptr)
|
||||
;; - `c`: char
|
||||
;; @todo Implement decimal, test X
|
||||
;; @param ARG0-1: Format string address
|
||||
;; @param ARG2-3: Output string address
|
||||
;; @param ARG4+: Additional parameters
|
||||
|
@ -1,6 +1,13 @@
|
||||
.ifndef INCLUDE_UTILITY
|
||||
INCLUDE_UTILITY = 1
|
||||
|
||||
|
||||
;;********************************************************************************
|
||||
;; @file
|
||||
;; @brief Various useful macros
|
||||
;; @ingroup utility
|
||||
;;********************************************************************************
|
||||
|
||||
.macpack longbranch ; jeq, jge...
|
||||
.macpack generic ; bge, add, sub
|
||||
|
||||
@ -190,7 +197,7 @@ _n_genlabel .set 0
|
||||
|
||||
.import REVERSE_TABLE
|
||||
;;********************************************************************************
|
||||
;; @macro Reverse a byte
|
||||
;; @macro Reverse a byte using a @ref REVERSE_TABLE "table"
|
||||
;; @param reg: The byte to reverse. May be in X, Y or A
|
||||
;; @returns A: The reversed byte
|
||||
;; @modifies A, X (only when reg = A)
|
||||
|
Loading…
Reference in New Issue
Block a user