From 7214f1fe6fbf21a0d06793b79e841675337ca0eb Mon Sep 17 00:00:00 2001 From: "matthias@rpi" Date: Thu, 26 Oct 2023 19:51:20 +0200 Subject: [PATCH] initial commit --- .dependencies | 4 + .gitignore | 2 + Makefile | 28 ++++++ details.md | 16 ++++ dht.s65 | 155 +++++++++++++++++++++++++++++++ linker.conf | 7 ++ main.s65 | 148 ++++++++++++++++++++++++++++++ programs/dht.s65 | 147 ++++++++++++++++++++++++++++++ programs/printer.s65 | 20 ++++ readme.md | 19 ++++ system/io_W65C22.h65 | 49 ++++++++++ system/keypad.s65 | 117 ++++++++++++++++++++++++ system/lcd.s65 | 211 +++++++++++++++++++++++++++++++++++++++++++ system/spi.s65 | 41 +++++++++ system/system.h65 | 78 ++++++++++++++++ test.s65 | 58 ++++++++++++ utility.s65 | 23 +++++ 17 files changed, 1123 insertions(+) create mode 100644 .dependencies create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 details.md create mode 100644 dht.s65 create mode 100644 linker.conf create mode 100644 main.s65 create mode 100644 programs/dht.s65 create mode 100644 programs/printer.s65 create mode 100644 readme.md create mode 100644 system/io_W65C22.h65 create mode 100644 system/keypad.s65 create mode 100644 system/lcd.s65 create mode 100644 system/spi.s65 create mode 100644 system/system.h65 create mode 100644 test.s65 create mode 100644 utility.s65 diff --git a/.dependencies b/.dependencies new file mode 100644 index 0000000..e442d9c --- /dev/null +++ b/.dependencies @@ -0,0 +1,4 @@ +../rom.bin: main.asm6502 system/system.asm6502 system/io_W65C22.asm6502 utility.asm6502 /usr/share/cc65/asminc/longbranch.mac system/lcd.asm6502 utility.asm6502 system/keypad.asm6502 programs/printer.asm6502 programs/dht.asm6502 + +main.asm6502 system/system.asm6502 system/io_W65C22.asm6502 utility.asm6502 /usr/share/cc65/asminc/longbranch.mac system/lcd.asm6502 utility.asm6502 system/keypad.asm6502 programs/printer.asm6502 programs/dht.asm6502: + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53f2d5c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +**.bin +**.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b0b80d0 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +ROM = ../rom.bin +MAIN = main.asm6502 + +BUILD_DIR = .build + +SRC_DIRS = programs system + +# VASM = ~/6502/vasm6502 +ASM = ca65 +ASMFLAGS = --cpu 65C02 $(foreach srcdir, $(SRC_DIRS), -I $(srcdir)) +ASMDEPFLAGS = --create-dep .dependencies + +LD = ld65 +LDFLAGS = -C linker.conf + +# DEPENDS = $(shell $(VASM) -depend=make $(MAIN)) + +-include .dependencies + +default: $(ROM) +$(ROM): + $(ASM) $(ASMFLAGS) $(ASMDEPFLAGS) $(MAIN) -o $@ + +.PHONY = test +test: + # $(VASM) -dotdir -opt-branch -wdc02 -chklabels test.asm6502 + $(ASM) $(ASMFLAGS) test.asm6502 -o test.o + $(LD) $(LDFLAGS) test.o -o test.bin diff --git a/details.md b/details.md new file mode 100644 index 0000000..1d52141 --- /dev/null +++ b/details.md @@ -0,0 +1,16 @@ +# Project details +## Address Space +### RAM: $0-$7fff +### (EEP)ROM: $8000-$ffff + +## Naming conventions +leading underscors `_` indicate a "private" label/variable, that is meant for internal use within the module only. +### Labels +- `namespace_fname` for exported subroutines +- `_namespace_fname` or `_namespace_fname_sub` for internal labels +- `(_)namespace_LABELNAME` for labels to data sections + +### Symbols/Macros +- `(_)NAMESPACE_SYMBOLNAME` for symbols +- `(_)NAMESPACE_macroname + diff --git a/dht.s65 b/dht.s65 new file mode 100644 index 0000000..2ed1f58 --- /dev/null +++ b/dht.s65 @@ -0,0 +1,155 @@ +;******************************************************************************** +; @module SPI +; @type driver +; @details +; @depends IO-W65C22N +;******************************************************************************** + +;TODO EVERYTHING +DHT_REQUEST_L = $00 +DHT_REQUEST_H = %01010000 ; = 20480 PHI2 pulses = 20,5 ms at 1 MHz + +DHT_RECV_H = %10011100 +DHT_RECV_L = %01000000 ; = 40000 PHI2 = 40ms + +; Status Variables, Used to determine what is sent by temp module +DHT_STATUS = $400 +DHT_NONE = 0 +DHT_WAIT_REQ = 1 +DHT_WAIT_RESP = 2 +DHT_RECV = 3 +DHT_DONE = 4 + +DHT_BIT = $401 +DHT_BIT_ROT = $402 + + +DHT_VALUES = $405 ; +DHT_OFFSET = $403 +DHT_OFF_RH_HIGH = 0 ; offsets to DHT_VALUES +DHT_OFF_RH_LOW = 1 +DHT_OFF_T_HIGH = 2 +DHT_OFF_T_LOW = 3 +DHT_OFF_CHECKSUM = 4 +DHT_OFF_DONE = 5 + + +message_dht: .asciiz "DHT-Request gesendet." +dht_wait: + ldx #$00 +dht_wait_: + lda message_dht,x + sta TO_PRINT,x + inx + bne dht_wait_ + jsr lcd_print_clear +dht_wait_loop: ; check after every interrpt if dht program is done and then return home + lda #'.' + jsr _lcd_char + wai + lda DHT_STATUS + cmp #DHT_DONE + bne dht_wait_loop + +dht_exit: + jsr kb_read + cmp #'*' + jeq home + bra dht_exit + jmp return_home + +dht_request: ; send request to sensor + sei + + lda #%00000001 ; set PA1-0 to output 0 + ora DDRA1 + sta DDRA1 + lda #(LCD_CLEAR | $00) + sta PA1 + + ; start timer + lda #DHT_REQUEST_L + sta T1L1 + lda #DHT_REQUEST_H + sta T1H1 + + lda #DHT_WAIT_REQ + sta DHT_STATUS + + cli + jmp dht_wait + + +dht_request_end: + lda #%10000010 + sta IER2 ; enable Interrupt for CA1 + lda #%11111110 + and DDRA1 + sta DDRA1 ; set PA1-0 to input + + lda #DHT_WAIT_RESP + + + +dht_response: ; receive response from sensor + lda #DHT_RECV + sta DHT_STATUS + stz DHT_OFFSET + lda #7 + sta DHT_BIT + +dht_recv: + ; start timer + lda #DHT_RECV_L + sta T1L1 + lda #DHT_RECV_H + sta T1H1 + rts + +dht_recv_read: + ; read PA2 + lda PA2 + and #%00000001 + ldx DHT_BIT + beq dht_recv_end +dht_recv_rot: + rol + dex + bne dht_recv_rot +dht_recv_end: + ldy DHT_OFFSET + ora DHT_VALUES,y + sta DHT_VALUES,y + ; determine if 8 bits are done + ldx DHT_BIT + beq dht_recv_next + rts +dht_recv_next: + lda #7 + sta DHT_BIT + inc DHT_OFFSET + cmp DHT_OFF_DONE + beq dht_display + rts + +dht_display: + ldx #0 +dht_display_: + lda DHT_VALUES,x + sta TO_PRINT,x + inx + cpx #5 + bne dht_display_ + jsr lcd_print_clear + rts + +dht_irq: + lda DHT_STATUS + cmp #DHT_WAIT_REQ + beq dht_request_end + cmp #DHT_WAIT_RESP + beq dht_response + cmp #DHT_RECV + beq dht_recv + rts + diff --git a/linker.conf b/linker.conf new file mode 100644 index 0000000..fb877f4 --- /dev/null +++ b/linker.conf @@ -0,0 +1,7 @@ +MEMORY { + ROM: start = $8000, size = $8000, file = %O, fill = yes; +} +SEGMENTS { + CODE: load = ROM, type = ro; + RESET_VECTOR: load = ROM, type = ro, start = $FFFA; +} diff --git a/main.s65 b/main.s65 new file mode 100644 index 0000000..2c595dd --- /dev/null +++ b/main.s65 @@ -0,0 +1,148 @@ +.include "system/system.h65" +.org $8000 ; EEPROM Start Address + +;******************************************************************************** +; Interrupts +;******************************************************************************** +nmi: + rti +irq: + ; lda IFR2 todo: verify that the line below does the same thing + lda IO2+IO_IFR + sta 0 + ; todo: decide wether to read keypad or dht + ora #%10100000 + ; jsr lcd_char ;TODO: Remove + jsr kp_read + rti + bbs1 0,irq_keypad + lda #'-' + jsr _lcd_char + bbs4 0,irq_dht + bbs6 0,irq_dht + rti +irq_keypad: + jsr kp_read + rti +irq_dht: + lda T1L2 ; clear interrupt flag + jsr dht_irq + rti + +;******************************************************************************** +; Reset sequence +;******************************************************************************** +reset: + lda #%11111111 + sta IO2 + IO_DDRA +.macro SET_DEBUG_LED_OFF + lda #%00000000 + sta IO2 + IO_RANH +.endmacro +.macro SET_DEBUG_LED_ON + lda #%11111111 + sta IO2 + IO_RANH +.endmacro + SET_DEBUG_LED_OFF + jsr lcd_init + + SET_DEBUG_LED_ON + ; jsr kp_init + + ; INIT DHT + lda #%11000010 ; enable interrupt for Timer 1 and CA1 on IO2 + sta IER2 + lda #%00111111 ; set Timer 1 to interrupt when loaded + and ACR2 + sta ACR2 + lda #%00000001 ; set PCR2 bit 0 CA1 pos edge interrupt + ora PCR2 + sta PCR2 + stz DHT_STATUS + + ; enable interrupts + cli + +.proc return_home + ldx #$00 +@return_home: + lda menu,x + beq @return_home_done + sta TO_PRINT,x + inx + bra @return_home +@return_home_done: + jsr lcd_print_clear +.endproc + +.proc home + jsr kb_read + beq home + cmp #'A' + jeq printer + cmp #'B' + jeq dht_request + cmp #'C' + beq print_1 + cmp #'D' + beq print_2 + + cmp #'*' ; print home menu again if not visible (message 1 and 2 jmp to home) + beq return_home + + bra home +.endproc + +print_1: + ldx #$00 +@print_1: + lda message_1,x + sta TO_PRINT,x + inx + bne @print_1 + jsr lcd_print_clear + jmp home + +print_2: + ldx #$00 +@print_2: + lda message_2,x + sta TO_PRINT,x + inx + bne @print_2 + jsr lcd_print_clear + jmp home + +.rodata +message_1: .asciiz " Powered by ......6502...... **** www.quintern.xyz" +message_2: .asciiz " Danke fuer eure Aufmerksamkeit ;) " +menu: + .byte " Printer " + .byte " Temperatur " + .byte " Text 1 " + .asciiz " Text 2 " + +.code +;******************************************************************************** +; Modules +;******************************************************************************** +; LCD + ; .include "utility.asm6502" +LCD_IO = IO1 + .include "lcd.asm6502" +; Keypad Reading +KP_IO = IO1 + .include "keypad.asm6502" +; Printer + .include "printer.asm6502" +; Digital Humidity and Temerature Sensor + .include "dht.asm6502" +;******************************************************************************** +; reset vector +;******************************************************************************** + +.rodata +.org $fffa + .word nmi + .word reset + .word irq diff --git a/programs/dht.s65 b/programs/dht.s65 new file mode 100644 index 0000000..97e5adf --- /dev/null +++ b/programs/dht.s65 @@ -0,0 +1,147 @@ +DHT_REQUEST_L = $00 +DHT_REQUEST_H = %01010000 ; = 20480 PHI2 pulses = 20,5 ms at 1 MHz + +DHT_RECV_H = %10011100 +DHT_RECV_L = %01000000 ; = 40000 PHI2 = 40ms + +; Status Variables, Used to determine what is sent by temp module +DHT_STATUS = $400 +DHT_NONE = 0 +DHT_WAIT_REQ = 1 +DHT_WAIT_RESP = 2 +DHT_RECV = 3 +DHT_DONE = 4 + +DHT_BIT = $401 +DHT_BIT_ROT = $402 + + +DHT_VALUES = $405 ; +DHT_OFFSET = $403 +DHT_OFF_RH_HIGH = 0 ; offsets to DHT_VALUES +DHT_OFF_RH_LOW = 1 +DHT_OFF_T_HIGH = 2 +DHT_OFF_T_LOW = 3 +DHT_OFF_CHECKSUM = 4 +DHT_OFF_DONE = 5 + + +message_dht: .asciiz "DHT-Request gesendet." +dht_wait: + ldx #$00 +dht_wait_: + lda message_dht,x + sta TO_PRINT,x + inx + bne dht_wait_ + jsr lcd_print_clear +dht_wait_loop: ; check after every interrpt if dht program is done and then return home + lda #'.' + jsr _lcd_char + wai + lda DHT_STATUS + cmp #DHT_DONE + bne dht_wait_loop + +dht_exit: + jsr kb_read + cmp #'*' + jeq home + bra dht_exit + jmp return_home + +dht_request: ; send request to sensor + sei + + lda #%00000001 ; set PA1-0 to output 0 + ora DDRA1 + sta DDRA1 + lda #(LCD_CLEAR | $00) + sta PA1 + + ; start timer + lda #DHT_REQUEST_L + sta T1L1 + lda #DHT_REQUEST_H + sta T1H1 + + lda #DHT_WAIT_REQ + sta DHT_STATUS + + cli + jmp dht_wait + + +dht_request_end: + lda #%10000010 + sta IER2 ; enable Interrupt for CA1 + lda #%11111110 + and DDRA1 + sta DDRA1 ; set PA1-0 to input + + lda #DHT_WAIT_RESP + + + +dht_response: ; receive response from sensor + lda #DHT_RECV + sta DHT_STATUS + stz DHT_OFFSET + lda #7 + sta DHT_BIT + +dht_recv: + ; start timer + lda #DHT_RECV_L + sta T1L1 + lda #DHT_RECV_H + sta T1H1 + rts + +dht_recv_read: + ; read PA2 + lda PA2 + and #%00000001 + ldx DHT_BIT + beq dht_recv_end +dht_recv_rot: + rol + dex + bne dht_recv_rot +dht_recv_end: + ldy DHT_OFFSET + ora DHT_VALUES,y + sta DHT_VALUES,y + ; determine if 8 bits are done + ldx DHT_BIT + beq dht_recv_next + rts +dht_recv_next: + lda #7 + sta DHT_BIT + inc DHT_OFFSET + cmp DHT_OFF_DONE + beq dht_display + rts + +dht_display: + ldx #0 +dht_display_: + lda DHT_VALUES,x + sta TO_PRINT,x + inx + cpx #5 + bne dht_display_ + jsr lcd_print_clear + rts + +dht_irq: + lda DHT_STATUS + cmp #DHT_WAIT_REQ + beq dht_request_end + cmp #DHT_WAIT_RESP + beq dht_response + cmp #DHT_RECV + beq dht_recv + rts + diff --git a/programs/printer.s65 b/programs/printer.s65 new file mode 100644 index 0000000..f46d516 --- /dev/null +++ b/programs/printer.s65 @@ -0,0 +1,20 @@ +;******************************************************************************** +; Printing Program +;******************************************************************************** +.ifndef INCLUDE_PRINTER +INCLUDE_PRINTER = 1 + +printer: + stz LCD_CHARCOUNT + lda #%10000000 + jsr _lcd_cmd + lda #LCD_CMD_CLEAR + jsr _lcd_cmd +@printer: + jsr kb_read + beq @printer + cmp #'*' + jeq return_home + jsr _lcd_char + bra @printer +.endif diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..982455f --- /dev/null +++ b/readme.md @@ -0,0 +1,19 @@ +# 8-bit Breadboard Computer with W65C02S Processor +This repo contains the assembly code for my [6502-project](https://quintern.xyz/de/6502.html). + +The assembler used for this project is [vasm](http://www.compilers.de/vasm.html). +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. + +> It's not much, but it's honest work. + +## Debug-Utility (with Raspberry Pi 4) +`monitor.py` is a python program to monitor the address-bus, data-bus and the read-write pin of the computer. It prints the current address and data in binary and hexadecimal on each clock cycle. diff --git a/system/io_W65C22.h65 b/system/io_W65C22.h65 new file mode 100644 index 0000000..9811c5c --- /dev/null +++ b/system/io_W65C22.h65 @@ -0,0 +1,49 @@ +;******************************************************************************** +; @module IO-W65C22 +; @type utility +; @device Western Design - W65C22N Versatile Interface Adapter +; @details +;******************************************************************************** + +.ifndef INCLUDE_IOW65C22 +INCLUDE_IOW65C22 = 1 + +; IO-CHIPS OFFSETS FOR PINS FROM BASE ADDRESS +IO_RB = $0 +IO_RA = $1 +IO_DDRB = $2 +IO_DDRA = $3 +IO_T1CL = $4 +IO_T1CH = $5 +IO_T1LL = $6 +IO_T1LH = $7 +IO_T2CL = $8 +IO_T2CH = $9 +IO_SR = $a +IO_ACR = $b +IO_PCR = $c +IO_IFR = $d +IO_IER = $e +IO_RANH = $f ; no handshake + + ; TODO: leave? + .struct VIA_Pins + RB .byte ; $0 + RA .byte ; $1 + DDRB .byte ; $2 + DDRA .byte ; $3 + T1CL .byte ; $4 + T1CH .byte ; $5 + T1LL .byte ; $6 + T1LH .byte ; $7 + T2CL .byte ; $8 + T2CH .byte ; $9 + SR .byte ; $a + ACR .byte ; $b + PCR .byte ; $c + IFR .byte ; $d + IER .byte ; $e + RANH .byte ; $f ; no handshake + .endstruct +.endif + diff --git a/system/keypad.s65 b/system/keypad.s65 new file mode 100644 index 0000000..d487461 --- /dev/null +++ b/system/keypad.s65 @@ -0,0 +1,117 @@ +;******************************************************************************** +; @module 4x4 Keypad +; @type driver +; @device 4x4 Matrix Keypad +; @details +; Keypad must be connected to a VIA +; @requires KP_IO: Base Address of IO Chip +; @depends IO-W65C22N +;******************************************************************************** + +.ifndef INCLUDE_KEYPAD +INCLUDE_KEYPAD = 1 +.ifndef KP_IO + .fatal "KP_IO is not defined: set it to the base address of the IO chip of the Keypad" +.endif + +;******************************************************************************** +; Keypad Buffer from $202 to $2ff +;******************************************************************************** +KB_VAR = $00 +KB_WRITE = $200 +KB_READ = $201 +KB_START = $202 +KB_LENGTH = $fd + +kb_init: + stz KB_WRITE + stz KB_READ + ; write null to entire buffer + ldx #$00 +@kb_init_loop: + stz KB_START,x + inx + cpx #KB_LENGTH + bne @kb_init_loop + rts + +; read from keybuffer, if empty null will be read +kb_read: + ldx KB_READ + lda KB_START,x + beq @kb_read_rts ; if a buffer is null, dont increment KB_READ + stz KB_START,x ; set buffer location to null + inx ; increment KB_READ pointer + cpx #KB_LENGTH + beq @kb_read_jump + stx KB_READ +@kb_read_rts: + rts +@kb_read_jump: + stz KB_READ + rts + +; write to keybuffer +_kb_write: + lda kp_VALUES, x ; load the char in a + ldx KB_WRITE + sta KB_START,x + inx ; increment KB_WRITE pointer + cpx #KB_LENGTH + beq @kb_jump_write + stx KB_WRITE + rts +@kb_jump_write: ; when the end of the buffer is reached, the next keys go to the start again + stz KB_WRITE + rts + +kp_init: + ; INIT KEYPAD + lda #%00001111; KP_IO+IO_RB 0-3 output + sta KP_IO+IO_DDRB + stz KP_IO+IO_RB ; KP_IO+IO_RB 4-7 1 so keypad press can be detected + stz KP_IO+IO_ACR + + lda #%10010000 ; enable interrupt for CB1 on KP_IO+IO_IO + sta KP_IO+IO_IER + lda #%00010000 ; set CB1 to interrupt on pos. edge + sta KP_IO+IO_PCR + jsr kb_init ; init keybuffer + rts + +;******************************************************************************** +; Reading the Keypad +;******************************************************************************** +kp_read: ; test each "row" and check which column is 1 + lda #%00001110 + ldx #$00 + jsr @kp_read_branch + lda #%00001101 + ldx #$04 + jsr @kp_read_branch + lda #%00001011 + ldx #$08 + jsr @kp_read_branch + lda #%00000111 + ldx #$0c + jsr @kp_read_branch +@kp_read_rts: + stz KP_IO+IO_RB + lda KP_IO+IO_RB ; read to definetly clear the interrupt flag + rts +@kp_read_branch: + sta KP_IO+IO_RB + lda KP_IO+IO_RB + sta KB_VAR ; store result in zeropage so that bbr can be used + bbr4 KB_VAR,_kb_write + inx + bbr5 KB_VAR,_kb_write + inx + bbr6 KB_VAR,_kb_write + inx + bbr7 KB_VAR,_kb_write + rts +kp_VALUES: + ; TODO change to literal + .byte "123A", "456B", "789C", "*0#D" +.endif diff --git a/system/lcd.s65 b/system/lcd.s65 new file mode 100644 index 0000000..3bcd825 --- /dev/null +++ b/system/lcd.s65 @@ -0,0 +1,211 @@ +;******************************************************************************** +; @module LCD-W164B +; @type driver +; @device ELECTRONIC ASSEMBLY - W164B-NLW +; @details +; Assumes it is connected to a W65C22N Interface Chip: +; - IO.RB0-7 -> LCD.D0-7 data lines +; - IO.RA5 -> LCD.RS register select +; - IO.RA6 -> LCD.R/W read/write +; - IO.RA7 -> LCD.E enable +; +; @requires LCD_IO: Base Address of IO Chip +; @optparam LCD_MEM: Address to a block of memory 1B. Default = $300 +; @depends IO-W65C22N +;******************************************************************************** + + .ifndef LCD_IO + .fatal "LCD_IO is not defined: set it to the base address of the IO chip of the LCD" + .endif + + .ifndef INCLUDE_IOW65C22 + .error "IO-W65C22 module is not included" + .endif + + .include "utility.asm6502" + + +; RAM VARIABLES + .ifndef LCD_MEM +LCD_MEM = $300 + .endif +LCD_CHARCOUNT = LCD_MEM + +; PIN MASKS +LCD_E = %10000000 +LCD_RW = %01000000 +LCD_RS = %00100000 + ; .local LCD_E,LCD_RW,LCD_RS + +; LCD Instructions +LCD_CMD_CLEAR = %00000001 ; clear display +LCD_CMD_ENTRY_MODE = %00000110 ; auto-shift cursor +LCD_CMD_DISPLAY_ON = %00001111 ; everything on, with blinking cursor +LCD_CMD_FUNCTION_SET = %00111000 ; 8-bit, 4 lines, 5x7 font +LCD_CMD_SET_ADDRESS = %10000000 ; or with the address +; LCD Constants +LCD_LINE1 = $00 ; line 1 +LCD_LINE2 = $40 +LCD_LINE3 = $10 +LCD_LINE4 = $50 + +LCD_CLEAR = %00000000 + + +;******************************************************************************** +; @function Initialize the lcd module +; @details call before doing anything else +;******************************************************************************** +.proc lcd_init + ; init IO + lda #$ff ; RB 0-7 output + sta LCD_IO+IO_DDRB + + UT_update_with_mask LCD_IO + IO_DDRA, (LCD_RS | LCD_RW | LCD_E), (LCD_RS | LCD_RW | LCD_E) + ; lda #(LCD_RS | LCD_RW | LCD_E) ; RA 5-7 output + ; sta LCD_IO+IO_DDRA + + ; init lcd + lda #LCD_CMD_FUNCTION_SET + jsr _lcd_cmd + lda #LCD_CMD_DISPLAY_ON + jsr _lcd_cmd + lda #LCD_CMD_CLEAR + jsr _lcd_cmd + lda #LCD_CMD_ENTRY_MODE + jsr _lcd_cmd + + stz LCD_CHARCOUNT + rts +.endproc + +;******************************************************************************** +; PRINTING TO LCD +;******************************************************************************** +_lcd_clear: ; clear lcd + stz LCD_CHARCOUNT + lda #LCD_CLEAR + jsr _lcd_cmd + lda #(LCD_CMD_SET_ADDRESS | LCD_LINE1) + jsr _lcd_cmd + rts + +;******************************************************************************** +; @function Clear the display and print a null-terminated string +; @see lcd_print +;******************************************************************************** +lcd_print_clear: ; clear lcd and print word located at message + stz LCD_CHARCOUNT + lda #LCD_CLEAR + jsr _lcd_cmd + lda #(LCD_CMD_SET_ADDRESS | LCD_LINE1) + jsr _lcd_cmd + +;******************************************************************************** +; @function Print a null-terminated string +; @param ARG0-1 Address of the string to print +;******************************************************************************** +lcd_print: + ldx #$00 +_lcd_print_loop: + lda (ARG0,x) + beq _lcd_print_end + jsr _lcd_char + inx + bra _lcd_print_loop +_lcd_print_end: + rts + +;******************************************************************************** +; LCD Commands +;******************************************************************************** +; read busy flag +_lcd_wait_nbusy: + stz LCD_IO + IO_DDRB ; set IO1-LCD_IO + IO_RB to input +@lcd_wait_nbusy_loop: ; read the busy flag + lda #LCD_RW + sta LCD_IO + IO_RA + lda #(LCD_RW | LCD_E) + sta LCD_IO + IO_RA + + lda LCD_IO + IO_RB + and #%10000000 ; and updates zero flag, if not set retry + bne @lcd_wait_nbusy_loop + + lda #%00000000 ; TODO dont overwrite 0-4 + sta LCD_IO + IO_RA + lda #%11111111 ; set IO1-LCD_IO + IO_RB to output + sta LCD_IO + IO_DDRB + rts + +_lcd_cmd: ; send cmd in acc + pha + jsr _lcd_wait_nbusy + pla + + ; TODO use UT_update_with_mask? + sta LCD_IO + IO_RB + lda #LCD_CLEAR + sta LCD_IO + IO_RA + lda #LCD_E + sta LCD_IO + IO_RA + lda #LCD_CLEAR + sta LCD_IO + IO_RA + rts + +_lcd_char: + pha + pha + ; TODO use UT_update_with_mask? + jsr _lcd_wait_nbusy + pla + sta LCD_IO + IO_RB + lda #LCD_RS + sta LCD_IO + IO_RA + lda #(LCD_RS | LCD_E) + sta LCD_IO + IO_RA + lda #LCD_RS + sta LCD_IO + IO_RA + inc LCD_CHARCOUNT + jsr _lcd_set_address + pla ; put char back in a + +;******************************************************************************** +; Set the LCD DD-RAM Address so that text linebreaks after 16 chars +;******************************************************************************** +_lcd_set_address: + ; check if checks are necessary + lda LCD_CHARCOUNT + beq @lcd_line1 + and #%10001111 ; ($10 | $20 | $30 | $40) = %01110000 + bne @lcd_set_address_done + ; checks necessary + lda LCD_CHARCOUNT + beq @lcd_line1 + cmp #$10 + beq @lcd_line2 + cmp #$20 + beq @lcd_line3 + cmp #$30 + beq @lcd_line4 + cmp #$40 ; set to line1 when full ; set to line1 when full + beq @lcd_line1 +@lcd_set_address_done: + rts +@lcd_line1: + stz LCD_CHARCOUNT + lda #(LCD_CMD_SET_ADDRESS | LCD_LINE1) + jsr _lcd_cmd + rts +@lcd_line2: + lda #(LCD_CMD_SET_ADDRESS | LCD_LINE2) + jsr _lcd_cmd + rts +@lcd_line3: + lda #(LCD_CMD_SET_ADDRESS | LCD_LINE3) + jsr _lcd_cmd + rts +@lcd_line4: + lda #(LCD_CMD_SET_ADDRESS | LCD_LINE4) + jsr _lcd_cmd + rts diff --git a/system/spi.s65 b/system/spi.s65 new file mode 100644 index 0000000..0af61ce --- /dev/null +++ b/system/spi.s65 @@ -0,0 +1,41 @@ +;******************************************************************************** +; @module SPI +; @type driver +; @details +; @depends IO-W65C22N +;******************************************************************************** + + .include "system/system.h65" + +.ifndef INCLUDE_SPI +INCLUDE_SPI = 1 + + .segment "CODE" + + .struct SPI_Pins + ; VIA addresses + DDR_a .word ; address of the data direction register + R_a .word ; address of the register + ; pin mask + SLK_p .byte ; Serial Clock + POCI_p .byte ; Peripheral Out / Controller In + PICO_p .byte ; Peripheral In / Controller Out + CSB_p .byte ; Chip Select + ; settings + CPOL .byte ; Clock Polarity + CPHA .byte ; Clock Phase + .endstruct + +;******************************************************************************** +; @function Send bytes +; @param X Number of bytes to send +; @param ARG0-1 Address of the first byte +; @param ARG2-3 Address of the SPI_Pins struct +;******************************************************************************** +send_data: + + + +_send_byte: + +.endif diff --git a/system/system.h65 b/system/system.h65 new file mode 100644 index 0000000..f9bbacb --- /dev/null +++ b/system/system.h65 @@ -0,0 +1,78 @@ +;******************************************************************************** +; @module system +; @type header +; @details +; Variable definitions for the current hardware setup +;******************************************************************************** + +.ifndef INCLUDE_SYSTEM +INCLUDE_SYSTEM = 1 +; reserved RAM addresses +; 00-0f - free +; 10-1f - arguments / return values +; 20-ff - free +; 0100 - 01FF Stack +; 0200,0201 keybuffer write/read pointer +; 0202 - 02ff keybuffer +; 0300 lcd character counter +; 0301 - 0341 message to print +; 0400, 0401, 0402 dht status, dht bit, dht_bit_rot +; 0403 value offset +; 0405 - 04a0 rh high/low, temp high/low, checksum + +TO_PRINT = $300 + +; ARGUMENTS +; a,x,y can also be used +ARG0 = $10 +ARG1 = $11 +ARG2 = $12 +ARG3 = $13 +ARG4 = $14 +ARG5 = $15 +ARG6 = $16 +ARG7 = $17 +ARG9 = $19 +ARG10 = $1a +ARG11 = $1b +ARG12 = $1c +ARG13 = $1d +ARG14 = $1e +ARG15 = $1f + +.include "io_W65C22.asm6502" +.include "utility.asm6502" + +; RETURN VALUE +; in a + +IO1 = $6000 +IO2 = $7000 + +; struct method + .org $6000 +VIA1: .tag VIA_Pins + .org $7000 +VIA2: .tag VIA_Pins + +; IO-1 +PB1 = $6000 +PA1 = $6001 +DDRB1 = $6002 +DDRA1 = $6003 +T1L1 = $6004 +T1H1 = $6005 +; IO-2 +PB2 = $7000 +PA2 = $7001 +DDRB2 = $7002 +DDRA2 = $7003 +T1L2 = $7004 +T1H2 = $7005 +ACR2 = $700b +PCR2 = $700c +IFR2 = $700d +IER2 = $700e + + +.endif ; include guard diff --git a/test.s65 b/test.s65 new file mode 100644 index 0000000..5dd50d9 --- /dev/null +++ b/test.s65 @@ -0,0 +1,58 @@ +.include "system/system.asm6502" +.segment "CODE" + +;******************************************************************************** +; Interrupts +;******************************************************************************** +nmi: + rti +irq: + nop + nop + nop + nop + + nop + nop + nop + nop + + nop + nop + nop + nop + + nop + nop + rti + +;******************************************************************************** +; Reset sequence +;******************************************************************************** +reset: + sei + ; setup io2 bank a 1-3 + lda #%11111111 + sta IO1 + IO_DDRA + +@loop: + lda #%00000000 + sta IO1 + IO_RANH + .repeat 3 + nop + .endrepeat + lda #%11111111 + sta IO1 + IO_RANH + .repeat 5 + nop + .endrepeat + bra @loop + +;******************************************************************************** +; reset vector +;******************************************************************************** +.segment "RESET_VECTOR" + .word nmi + .word reset + .word irq + diff --git a/utility.s65 b/utility.s65 new file mode 100644 index 0000000..f9d00dd --- /dev/null +++ b/utility.s65 @@ -0,0 +1,23 @@ +.ifndef INCLUDE_UTILITY +INCLUDE_UTILITY = 1 + +.macpack longbranch ; jeq, jge... + +;******************************************************************************** +; @macro Update a byte in memory using a mask +; @param orignal Address of the byte to update +; @param new New value +; @param mask Mask of the bits to affect by the new value +; @details +; xor new with original -> only bits that need to flip are 1 +; and result with mask -> only selected bits that need to flip stay 1 +; xor result with original -> flips selected bits +;******************************************************************************** +.macro UT_update_with_mask original,new,mask + lda #new + eor original + and #mask + eor original + sta original +.endmacro +.endif