commit 7214f1fe6fbf21a0d06793b79e841675337ca0eb Author: matthias@rpi Date: Thu Oct 26 19:51:20 2023 +0200 initial commit 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