diff --git a/.gitignore b/.gitignore index a930983..919eb03 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.bin *.rom -*.asm +.#* +tools/otb-convert +tools/term \ No newline at end of file diff --git a/Makefile b/Makefile index cb3dbc1..f2d8fb9 100644 --- a/Makefile +++ b/Makefile @@ -14,11 +14,29 @@ all: %.prog: %.rom minipro -p AT28C256 -w $< +%.term: %.bin + ./tools/term $< + clean: rm -f *.bin *.rom + rm -f $(basename $(wildcard *.in)) + rm -f $(basename $(wildcard */*.in)) aoc/2020/day1/solution.bin: aoc/2020/day1/solution.asm aoc/mul24.asm aoc/hex.asm aoc/lcd.asm aoc/2020/day1/input.bin +oled.bin: oled.asm face.bin + +res/keymap.bin: tools/keymap.py + python tools/keymap.py res/keymap.bin + +keyboard.bin: keyboard.asm character-lcd.asm keymap.bin + +keyboard2.bin: keyboard2.asm character-lcd.asm keymap.bin + +graphic-font.bin: graphic-font.asm graphic-lcd.asm res/font.bin + +keyboard3.bin: keyboard3.asm graphic-lcd.asm graphic-font.asm res/font.bin res/keymap.bin + .SUFFIXES: .INTERMEDIATE: .PRECIOUS: %.bin %.rom %.asm diff --git a/blink.asm b/blink.asm index db981af..cb9b28b 100644 --- a/blink.asm +++ b/blink.asm @@ -11,4 +11,4 @@ loop: LDA # 1 STA a 8000 ;; repeat - JMP a :loop + BRA r :loop diff --git a/blink2.asm.in b/blink2.asm.in new file mode 100644 index 0000000..67ed9d3 --- /dev/null +++ b/blink2.asm.in @@ -0,0 +1,21 @@ +include(`common.m4') + + LDA # 1 + STA a VIA1_DDRA + + LDA # 1 + STA a VIA2_DDRA + +loop: LDA # 1 + STA a VIA1_PORTA + + LDA # 0 + STA a VIA2_PORTA + + LDA # 0 + STA a VIA1_PORTA + + LDA # 1 + STA a VIA2_PORTA + + BRA r :loop diff --git a/bootloader.asm.in b/bootloader.asm.in new file mode 100644 index 0000000..ba122dd --- /dev/null +++ b/bootloader.asm.in @@ -0,0 +1,174 @@ +; -*-asm-*- +include(`common.m4') + + BRA r :reset ; RESB + JMP a 0202 ; IRQB + + ;; reset stack +reset: SEI i + + LDX # ff + TXS i + + ;; CS high, SCLK low + LDA # hh(M_CS) + STA a VIA2_PORTB + + LDA # hh(M_DDR_MASK) + STA a VIA2_DDRB + + LDX # hh(M_CFGH) + LDY # hh(M_CFGL_BAUD_115200) + JSR a :spi16 + +define(SPI_IN_H, 2)dnl +define(SPI_IN_L, 1)dnl + +define(SPI_OUT_H, 4)dnl +define(SPI_OUT_L, 3)dnl + +define(LDR_OFFSET, fc)dnl +define(LDR_LEN, fd)dnl +define(LDR_ADDR_L, fe)dnl +define(LDR_ADDR_H, ff)dnl + + ;; read header +;;; begin hdr_len + LDX # hh(M_W_DATAH|M_W_DATAH_TE|M_W_DATAH_RTS) + LDY # 0 + BRA r :_read_hdr_spi + +read_header: LDX # hh(M_W_DATAH|M_W_DATAH_RTS) + LDY zp SPI_OUT_L +_read_hdr_spi: JSR a :spi16 + + LDA zp SPI_OUT_H + BMI r :_hdr_len ; BMI = if the leftmost bit is 0 + +_wait_hdr_len: LDX # hh(M_W_DATAH|M_W_DATAH_TE|M_W_DATAH_RTS) + LDY # 0 + JSR a :spi16 + + LDA zp SPI_OUT_H + BPL r :_wait_hdr_len ; BPL = if the leftmost bit is 0 + +_hdr_len: LDA zp SPI_OUT_L + STA zp LDR_LEN +;;; end hdr_len + + +;;; begin hdr_al + LDX # hh(M_W_DATAH|M_W_DATAH_RTS) + LDY # 4c ; L + JSR a :spi16 + + LDA zp SPI_OUT_H + BMI r :_hdr_al ; BMI = if the leftmost bit is 0 + +_wait_hdr_al: LDX # hh(M_W_DATAH|M_W_DATAH_TE|M_W_DATAH_RTS) + LDY # 0 + JSR a :spi16 + + LDA zp SPI_OUT_H + BPL r :_wait_hdr_al ; BPL = if the leftmost bit is 0 + +_hdr_al: LDA zp SPI_OUT_L + STA zp LDR_ADDR_L +;;; end hdr_al + +;;; begin hdr_ah + LDX # hh(M_W_DATAH|M_W_DATAH_RTS) + LDY # 44 ; D + JSR a :spi16 + + LDA zp SPI_OUT_H + BMI r :_hdr_ah ; BMI = if the leftmost bit is 0 + +_wait_hdr_ah: LDX # hh(M_W_DATAH|M_W_DATAH_TE|M_W_DATAH_RTS) + LDY # 0 + JSR a :spi16 + + LDA zp SPI_OUT_H + BPL r :_wait_hdr_ah ; BPL = if the leftmost bit is 0 + +_hdr_ah: LDA zp SPI_OUT_L + STA zp LDR_ADDR_H +;;; end hdr_ah + + LDA zp LDR_LEN + BEQ r :_ldr_jump ; if (len == zero) goto _ldr_jump; + + STZ zp LDR_OFFSET + + LDX # hh(M_W_DATAH|M_W_DATAH_RTS) + LDY # 52 ; R + JSR a :spi16 + BRA r :_data_cmp + + ;; transfer data +wait_data: LDX # hh(M_W_DATAH|M_W_DATAH_TE|M_W_DATAH_RTS) + LDY # 0 + JSR a :spi16 + +_data_cmp: LDA zp SPI_OUT_H + BPL r :wait_data ; BPL = if the leftmost bit is 0 + +copy_fifo: LDY zp LDR_OFFSET + LDA zp SPI_OUT_L + STA (zp),y LDR_ADDR_L + INC zp LDR_OFFSET + DEC zp LDR_LEN + BEQ r :read_header + + LDX # hh(M_W_DATAH) + LDY zp SPI_OUT_L + JSR a :spi16 + + LDA zp SPI_OUT_H + BMI r :copy_fifo ; BMI = if the leftmost bit is 1 + + BRA r :wait_data + + +_ldr_jump: JMP (a) LDR_ADDR_L + + + ;; CS low, SCLK low +spi16: LDA # %00000000 + STA a VIA2_PORTB + + STX zp 2 + STY zp 1 + ;; SPI output + STZ zp 4 + STZ zp 3 + + LDX # 2 +_spi_next: LDY # 8 + STY zp 0 +_spi_8: ASL zp,x 0 + LDA # 0 ; preclear MOSI + BCC r :_spi_zout + ORA # hh(M_DIN) ; set MOSI +_spi_zout: STA a VIA2_PORTB + + ORA # hh(M_SCLK) ; set SCLK + STA a VIA2_PORTB + + LDY a VIA2_PORTB ; DOUT on bit 7 + CLC i ; preclear MISO + BPL r :_spi_zin ; + SEC i ; set MISO +_spi_zin: ROL zp,x 2 + + AND # hh(~M_SCLK & 0xff) ; clear SCLK + STA a VIA2_PORTB + + DEC zp 0 + BNE r :_spi_8 + DEX i + BNE r :_spi_next + ;; CS high, SCLK low + LDA # hh(M_CS) + STA a VIA2_PORTB + RTS s diff --git a/character-lcd.asm.in b/character-lcd.asm.in new file mode 100644 index 0000000..ff7740e --- /dev/null +++ b/character-lcd.asm.in @@ -0,0 +1,83 @@ +include(`common.m4') + +;;; begin lcd_init + ;; Set Port A to Output +lcd_init: LDA # hh(L_DDR_MASK) + STA a VIA0_DDRA + + ;; Function Set: + ;; D7 D6 D5 D4 D3 D2 D1 D0 + ;; 0 0 1 B L F x x + ;; (Bits 8/4, Lines 2/1, Font 5x11/5x8) + LDA # %00111000 + JSR a :lcd_w_rs0 + + ;; Display ON/OFF: + ;; D7 D6 D5 D4 D3 D2 D1 D0 + ;; 0 0 0 0 0 D C B + ;; (Display, Cursor, Blink) + LDA # %00001110 + JSR a :lcd_w_rs0 + + ;; Clear Display: + ;; D7 D6 D5 D4 D3 D2 D1 D0 + ;; 0 0 0 0 0 0 0 1 + LDA # %00000001 + JSR a :lcd_w_rs0 + + ;; Entry Mode Set: + ;; D7 D6 D5 D4 D3 D2 D1 D0 + ;; 0 0 0 0 0 1 I/D S + ;; (Increment/Decrement, Shift) + LDA # %00000110 + JSR a :lcd_w_rs0 + + RTS s +;;; end lcd_init + + ;; write "instruction" +lcd_w_rs0: JSR a :lcd_wait + + STA a VIA0_PORTB + LDA # 0 + STA a VIA0_PORTA + LDA # hh(C_E) + STA a VIA0_PORTA + LDA # 0 + STA a VIA0_PORTA + RTS s + + ;; write "data" to lcd +lcd_w_rs1: JSR a :lcd_wait + + STA a VIA0_PORTB + LDA # hh(C_RS) + STA a VIA0_PORTA + LDA # hh(C_RS|C_E) + STA a VIA0_PORTA + LDA # hh(C_RS) + STA a VIA0_PORTA + RTS s + + ;; wait BF +lcd_wait: PHA s + + LDA # %00000000 ;; Set pins 0-7 on Port B to Input + STA a VIA0_DDRB + +_lcd_wait: LDA # hh(C_RW) + STA a VIA0_PORTA + LDA # hh(C_E|C_RW) + STA a VIA0_PORTA + LDA a VIA0_PORTB + AND # %10000000 + BNE r :_lcd_wait + + LDA # hh(C_RW) + STA a VIA0_PORTA + + LDA # %11111111 ;; Set pins 0-7 on Port B to Output + STA a VIA0_DDRB + + PLA s + RTS s diff --git a/common.m4 b/common.m4 index b425f4d..0f3adeb 100644 --- a/common.m4 +++ b/common.m4 @@ -1,27 +1,109 @@ changecom(`@')dnl dnl -define(PORTB, 8000)dnl -define(PORTA, 8001)dnl -define(DDRB, 8002)dnl -define(DDRA, 8003)dnl -define(T1CL, 8004)dnl -define(T1CH, 8005)dnl -define(T1LL, 8006)dnl -define(T1LH, 8007)dnl -define(T2CL, 8008)dnl -define(T2CH, 8009)dnl -define(SR, 800a)dnl -define(ACR, 800b)dnl -define(PCR, 800c)dnl -define(IFR, 800d)dnl -define(IER, 800e)dnl +define(VIA0_PORTB, 8000)dnl +define(VIA0_PORTA, 8001)dnl +define(VIA0_DDRB, 8002)dnl +define(VIA0_DDRA, 8003)dnl +define(VIA0_T1CL, 8004)dnl +define(VIA0_T1CH, 8005)dnl +define(VIA0_T1LL, 8006)dnl +define(VIA0_T1LH, 8007)dnl +define(VIA0_T2CL, 8008)dnl +define(VIA0_T2CH, 8009)dnl +define(VIA0_SR, 800a)dnl +define(VIA0_ACR, 800b)dnl +define(VIA0_PCR, 800c)dnl +define(VIA0_IFR, 800d)dnl +define(VIA0_IER, 800e)dnl dnl -define(`L_CGRAM', `0b01000000')dnl -define(`L_DDRAM', `0b10000000')dnl +define(VIA1_PORTB, 8800)dnl +define(VIA1_PORTA, 8801)dnl +define(VIA1_DDRB, 8802)dnl +define(VIA1_DDRA, 8803)dnl +define(VIA1_T1CL, 8804)dnl +define(VIA1_T1CH, 8805)dnl +define(VIA1_T1LL, 8806)dnl +define(VIA1_T1LH, 8807)dnl +define(VIA1_T2CL, 8808)dnl +define(VIA1_T2CH, 8809)dnl +define(VIA1_SR, 880a)dnl +define(VIA1_ACR, 880b)dnl +define(VIA1_PCR, 880c)dnl +define(VIA1_IFR, 880d)dnl +define(VIA1_IER, 880e)dnl dnl -define(`L_E', `0b001')dnl -define(`L_RS', `0b010')dnl -define(`L_RW', `0b100')dnl +define(VIA2_PORTB, 9000)dnl +define(VIA2_PORTA, 9001)dnl +define(VIA2_DDRB, 9002)dnl +define(VIA2_DDRA, 9003)dnl +define(VIA2_T1CL, 9004)dnl +define(VIA2_T1CH, 9005)dnl +define(VIA2_T1LL, 9006)dnl +define(VIA2_T1LH, 9007)dnl +define(VIA2_T2CL, 9008)dnl +define(VIA2_T2CH, 9009)dnl +define(VIA2_SR, 900a)dnl +define(VIA2_ACR, 900b)dnl +define(VIA2_PCR, 900c)dnl +define(VIA2_IFR, 900d)dnl +define(VIA2_IER, 900e)dnl +dnl ACR +dnl ACR +define(`ACR_SR_DISABLED', `0b00000000')dnl +define(`ACR_SR_IN_T2', `0b00000100')dnl +define(`ACR_SR_IN_PHI2', `0b00001000')dnl +define(`ACR_SR_IN_CB1', `0b00001100')dnl +define(`ACR_SR_OUT_FREE_T2', `0b00010000')dnl +define(`ACR_SR_OUT_T2', `0b00010100')dnl +define(`ACR_SR_OUT_PHI2', `0b00011000')dnl +define(`ACR_SR_OUT_CB1', `0b00011100')dnl +dnl LCD common +define(`L_DDR_MASK', `0b11111111')dnl +dnl character LCD +define(`C_CGRAM', `0b01000000')dnl +define(`C_DDRAM', `0b10000000')dnl +dnl +define(`C_E', `0b00000001')dnl +define(`C_RS', `0b00010000')dnl +define(`C_RW', `0b00100000')dnl dnl define(`hh', `eval($1, 16)')dnl -define(`bh', `eval(0b$1, 16)')dnl +dnl graphic LCD +define(`G_E', `0b00000010')dnl +define(`G_C1', `0b00000100')dnl +define(`G_C2', `0b00001000')dnl +define(`G_RS', `0b00010000')dnl +define(`G_RW', `0b00100000')dnl +dnl MAX3100 +define(`M_DDR_MASK', `0b01110000')dnl +define(`M_DOUT', `0b10000000')dnl input +define(`M_DIN', `0b01000000')dnl output +define(`M_SCLK', `0b00100000')dnl output +define(`M_CS', `0b00010000')dnl output +dnl MAX3100 CFG bits +define(`M_CFGH', `0b11000000')dnl +define(`M_CFGH_FENB', `0b00100000')dnl 0=enable FIFO +define(`M_CFGH_SHDN', `0b00010000')dnl 1=shutdown +define(`M_CFGH_TMB', `0b00001000')dnl 1=enable transmit done interrupt +define(`M_CFGH_RMB', `0b00000100')dnl 1=enable data received interrupt +define(`M_CFGH_PMB', `0b00000010')dnl 1=enable parity interrupt +define(`M_CFGH_RAMB', `0b00000001')dnl 1=enable framing error interrupt +define(`M_CFGL_IR', `0b10000000')dnl 1=enable IrDA timing mode +define(`M_CFGL_ST', `0b01000000')dnl 1=two stop bits +define(`M_CFGL_PE', `0b00100000')dnl 1=parity enabled +define(`M_CFGL_L', `0b00010000')dnl 1=7-bits; 0=8-bits +define(`M_CFGL_BAUD_230400', `0b00000000')dnl +define(`M_CFGL_BAUD_115200', `0b00000001')dnl +define(`M_CFGL_BAUD_57600', `0b00000010')dnl +define(`M_CFGL_BAUD_38400', `0b00001001')dnl +define(`M_CFGL_BAUD_19200', `0b00001010')dnl +define(`M_CFGL_BAUD_9600', `0b00001011')dnl +define(`M_CFGL_BAUD_600', `0b00001111')dnl +dnl MAX3100 data bits +define(`M_R_DATA', `0b00000000')dnl +define(`M_W_DATAH', `0b10000000')dnl +define(`M_W_DATAH_TE', `0b00000100')dnl 1=inhibit TX +define(`M_W_DATAH_RTS', `0b00000010')dnl 1=drive RTS low; 0=drive RTS high +define(`M_W_DATAH_PT', `0b00000001')dnl 1=parity1; 0=parity0 +dnl bit7 high "data has been received" +dnl bit6 high "transmit buffer empty" diff --git a/graphic-font.asm.in b/graphic-font.asm.in new file mode 100644 index 0000000..ac5d416 --- /dev/null +++ b/graphic-font.asm.in @@ -0,0 +1,99 @@ +; -*-asm-*- +include(`common.m4') + +;; BRA r :_gfont_reset ; RESB +;; NOP i ; IRQ + +;; _gfont_reset: LDX # ff +;; TXS i + +;; JSR a :gfont_init + +;; LDA # ^97 +;; JSR a :gfont_draw_c2 + +;; stop: BRA r :stop + + ;; Set pins 0-4 on Port A to Output +gfont_init: LDA # hh(L_DDR_MASK) + STA a VIA0_DDRA + + ;; Display ON/OFF: + ;; D7 D6 D5 D4 D3 D2 D1 D0 + ;; 0 0 1 1 1 1 1 D + ;; + LDA # %00111111 + JSR a :glcd_w_rs0_c2 + LDA # %00111111 + JSR a :glcd_w_rs0_c1 + + STZ zp 0 + JSR a :glcd_fill + + LDA # %01000000 ; Y address + ORA # ^55 + JSR a :glcd_w_rs0_c2 + + LDA # %10111000 ; X page + ORA # ^7 + JSR a :glcd_w_rs0_c2 + + RTS s + + +;;; begin gfont_draw_c2 (A) + ;; begin A << 3 +gfont_draw_c2: STA zp 0 + STZ zp 1 + ASL zp 0 + ROL zp 1 + ASL zp 0 + ROL zp 1 + ASL zp 0 + ROL zp 1 + ;; end A << 3 + + CLC i + LDA # :_bin_res/font_start_l + ADC zp 0 + STA zp 0 + LDA # :_bin_res/font_start_h + ADC zp 1 + STA zp 1 + + LDY # 4 +_gfont_c2_y_loop: LDA (zp),y 0 + JSR a :glcd_w_rs1_c2 + DEY i + BPL r :_gfont_c2_y_loop + RTS s +;;; end gfont_draw_c2 + + +;;; begin gfont_draw_c1 (A) + ;; begin A << 3 +gfont_draw_c1: STA zp 0 + STZ zp 1 + ASL zp 0 + ROL zp 1 + ASL zp 0 + ROL zp 1 + ASL zp 0 + ROL zp 1 + ;; end A << 3 + + CLC i + LDA # :_bin_res/font_start_l + ADC zp 0 + STA zp 0 + LDA # :_bin_res/font_start_h + ADC zp 1 + STA zp 1 + + LDY # 4 +_gfont_c1_y_loop: LDA (zp),y 0 + JSR a :glcd_w_rs1_c1 + DEY i + BPL r :_gfont_c1_y_loop + RTS s +;;; end gfont_draw_c1 diff --git a/graphic-lcd.asm.in b/graphic-lcd.asm.in new file mode 100644 index 0000000..3ff37bc --- /dev/null +++ b/graphic-lcd.asm.in @@ -0,0 +1,131 @@ +include(common.m4) + +;;; begin glcd_init +glcd_fill: LDY # 00 + + LDA # %01000000 ; Y address + JSR a :glcd_w_rs0_c2 + + LDA # %01000000 ; Y address + JSR a :glcd_w_rs0_c1 + +_glcd_next_page: TYA i + ORA # %10111000 ; X page + JSR a :glcd_w_rs0_c2 + + TYA i + ORA # %10111000 ; X page + JSR a :glcd_w_rs0_c1 + + LDX # 40 +_glcd_fill_page: LDA zp 0 + JSR a :glcd_w_rs1_c2 + + LDA zp 0 + JSR a :glcd_w_rs1_c1 + + DEX i + BNE r :_glcd_fill_page + INY i + CPY # 8 + BNE r :_glcd_next_page + RTS s +;;; end glcd_init + + + ;; write "instruction" +glcd_w_rs0_c2: JSR a :glcd_wait_c2 + + STA a VIA0_PORTB + LDA # hh(G_C2) + STA a VIA0_PORTA + LDA # hh(G_C2|G_E) + STA a VIA0_PORTA + + LDA # hh(G_C2) + STA a VIA0_PORTA + + RTS s + +glcd_w_rs0_c1: JSR a :glcd_wait_c1 + + STA a VIA0_PORTB + LDA # hh(G_C1) + STA a VIA0_PORTA + LDA # hh(G_C1|G_E) + STA a VIA0_PORTA + LDA # hh(G_C1) + STA a VIA0_PORTA + + RTS s + + ;; write "data" to lcd +glcd_w_rs1_c2: JSR a :glcd_wait_c2 + + STA a VIA0_PORTB + LDA # hh(G_RS|G_C2) + STA a VIA0_PORTA + LDA # hh(G_RS|G_C2|G_E) + STA a VIA0_PORTA + LDA # hh(G_RS|G_C2) + STA a VIA0_PORTA + + RTS s + +glcd_w_rs1_c1: JSR a :glcd_wait_c1 + + STA a VIA0_PORTB + LDA # hh(G_RS|G_C1) + STA a VIA0_PORTA + LDA # hh(G_RS|G_C1|G_E) + STA a VIA0_PORTA + LDA # hh(G_RS|G_C1) + STA a VIA0_PORTA + + RTS s + + ;; wait BF +glcd_wait_c2: PHA s + + LDA # %00000000 ;; Set pins 0-7 on Port B to Input + STA a VIA0_DDRB + +_glcd_wait-c2: LDA # hh(G_RW|G_C2) + STA a VIA0_PORTA + LDA # hh(G_RW|G_C2|G_E) + STA a VIA0_PORTA + LDA a VIA0_PORTB + AND # %10000000 + BNE r :_glcd_wait-c2 + + LDA # hh(G_RW|G_C2) + STA a VIA0_PORTA + + LDA # %11111111 ;; Set pins 0-7 on Port B to Output + STA a VIA0_DDRB + + PLA s + RTS s + + ;; wait BF +glcd_wait_c1: PHA s + + LDA # %00000000 ;; Set pins 0-7 on Port B to Input + STA a VIA0_DDRB + +_glcd_wait-c1: LDA # hh(G_RW|G_C1) + STA a VIA0_PORTA + LDA # hh(G_RW|G_C1|G_E) + STA a VIA0_PORTA + LDA a VIA0_PORTB + AND # %10000000 + BNE r :_glcd_wait-c1 + + LDA # hh(G_RW|G_C1) + STA a VIA0_PORTA + + LDA # %11111111 ;; Set pins 0-7 on Port B to Output + STA a VIA0_DDRB + + PLA s + RTS s diff --git a/keyboard.asm.in b/keyboard.asm.in new file mode 100644 index 0000000..b4ed0b5 --- /dev/null +++ b/keyboard.asm.in @@ -0,0 +1,121 @@ +include(`common.m4') + +define(KBD_STATE, 0x40) ;;; 0x40 - 0x80 + + BRA r :reset ; RESB + NOP i ; IRQ + +reset: LDX # ff + TXS i + + JSR a :lcd_init + + ;; LDA # 61 + ;; JSR a :lcd_w_rs1 + + LDA # %11111111 + STA a VIA1_PORTA + + LDA # %00000000 + STA a VIA1_DDRB + + LDA # %11111111 + STA a VIA1_DDRA + + + LDX # 80 + LDA # f +_state: STA zp,x hh(KBD_STATE) + DEX i + BNE r :_state + + +forever: LDX # 7 ; state + LDA # %01111111 + STA zp 0 + +loop0: LDA zp 0 + STA a VIA1_PORTA + + LDY # 4 ; bit + LDA a VIA1_PORTB +loop1: ROR A + PHP s + PHA s + ;; (X * 8 + Y) * 2 + TYA i + STA zp 1 + TXA i + ASL A + ASL A + ASL A + CLC i + ADC zp 1 + ASL A + ;; + STX zp 1 + TAX i + PLP s + BCS r :_kbd_up + + LSR A ; + JSR a :lcd_w_rs1 ; + BPL r :_loop1_resume ; + +_kbd_down: DEC zp,x hh(KBD_STATE) + BPL r :_loop1_resume + BNE r :_key_not_yet_down + + ;; if (KBD_STATE[X][0] == 0) { + LSR A + TAX i + LDA a,x :_bin_keymap_start + JSR a :lcd_w_rs1 + ;; } + + +_key_not_yet_down: LDA # ff + STA zp,x hh(KBD_STATE) + LDA # f + STA zp,x hh(KBD_STATE + 1) + + BRA r :_loop1_resume +;;; Y is the offset of the current key +_kbd_up: DEC zp,x hh(KBD_STATE + 1) + BPL r :_loop1_resume + + LDA # ff + STA zp,x hh(KBD_STATE + 1) + LDA # f + STA zp,x hh(KBD_STATE) + +_loop1_resume: PLA s + LDX zp 1 + DEY i + BPL r :loop1 + + SEC i + ROR zp 0 + DEX i + BPL r :loop0 + + BRA r :forever + + + ;; LDA # %00000001 + ;; JSR a :lcd_w_rs0 + + ;; TXA i + ;; CLC i + ;; ADC # 30 + ;; STA a VIA1_PORTB + ;; JSR a :lcd_w_rs1 + + ;; LDA # 20 + ;; JSR a :lcd_w_rs1 + + ;; TYA i + ;; CLC i + ;; ADC # 30 + ;; STA a VIA1_PORTB + ;; JSR a :lcd_w_rs1 diff --git a/keyboard2.asm.in b/keyboard2.asm.in new file mode 100644 index 0000000..45bfa6e --- /dev/null +++ b/keyboard2.asm.in @@ -0,0 +1,116 @@ +include(`common.m4') + +define(KBD_STATE, 0x40) ;;; 0x40 - 0x7f +define(KBD_STATE2, 0x80) ;;; 0x80 - 0xbf + + BRA r :reset ; RESB + NOP i ; IRQ + +reset: LDX # ff + TXS i + + JSR a :lcd_init + + ;; LDA # 61 + ;; JSR a :lcd_w_rs1 + + LDA # %11111111 + STA a VIA1_PORTA + + LDA # %00000000 + STA a VIA1_DDRB + + LDA # %11111111 + STA a VIA1_DDRA + + + LDX # 80 + LDA # 0 +_state: STA zp,x hh(KBD_STATE) + DEX i + BNE r :_state + + +loop: LDX # 7 ; state + LDA # %01111111 + STA zp 0 + +loop0: LDA zp 0 + STA a VIA1_PORTA + + LDY # 4 ; bit + LDA a VIA1_PORTB +loop1: ROR A + PHA s ; [A] + PHP s ; [P,A] + ;; (X * 8 + Y) * 2 + TXA i + ASL A + ASL A + ASL A + CLC i + STY zp 1 + ADC zp 1 + ;; + + PLP s ; [A] + PHX s ; [X,A] + TAX i + BCS r :_kbd_up + +;;; down +_kbd_down: LDA zp,x hh(KBD_STATE) + CMP # 4 + BNE r :_kbd_state_inc + + ;; if (kbd_state == 0) + LDA a,x hh(KBD_STATE2) + BNE r :_loop1_resume + + INC a,x hh(KBD_STATE2) + + LDA a,x :_bin_keymap_start + JSR a :kbd_char + + BRA r :_loop1_resume + ;; } + +_kbd_state_inc: INC zp,x hh(KBD_STATE) + BRA r :_loop1_resume + +;;; end down + +_kbd_up: LDA zp,x hh(KBD_STATE) + BEQ r :_kbd_up_state2 + +_kbd_state_dec: DEC zp,x hh(KBD_STATE) + BRA r :_loop1_resume + +_kbd_up_state2: STZ a,x hh(KBD_STATE2) + +_loop1_resume: PLX s ; [A] + PLA s ; [] + DEY i + BPL r :loop1 + + SEC i + ROR zp 0 + DEX i + BPL r :loop0 + + BRA r :loop + +;;; kbd char +kbd_char: CMP # 30 + BEQ r :_backspace + + JSR a :lcd_w_rs1 + RTS s + + ;; CL + ;; 0001SRxx +_backspace: LDA a %00010000 + JSR a :lcd_w_rs0 + RTS s + +;;; end kbd_char diff --git a/keyboard3.asm.in b/keyboard3.asm.in new file mode 100644 index 0000000..b3d5a9e --- /dev/null +++ b/keyboard3.asm.in @@ -0,0 +1,277 @@ +include(`common.m4') + +define(KBD_STATE, 40) ;;; 0x40 - 0x7f +define(KBD_STATE2, 80) ;;; 0x80 - 0xbf + +define(KBD_COM_MASK, 3f) +define(KBD_GLCD_Y, 3e) +define(KBD_GLCD_X, 3d) +define(KBD_GLCD_C, 3c) +define(KBD_LAYER, 3b) + + BRA r :reset ; RESB + NOP i ; IRQ + +reset: LDX # ff + TXS i + + JSR a :gfont_init + ;; gfont_init already set Y and X to 55 and 7 + LDA # ^55 + STA zp KBD_GLCD_Y + JSR a :_kbd_char_c2_cursor + + LDA # ^7 + STA zp KBD_GLCD_X + + STZ zp KBD_GLCD_C + + STZ zp KBD_LAYER + + LDA # %11111111 + STA a VIA1_PORTA + + LDA # %00000000 + STA a VIA1_DDRB + + LDA # %11111111 + STA a VIA1_DDRA + + ;; layer indication + LDA # %00000011 + STA a VIA2_DDRA + + STZ a VIA2_PORTA + + LDX # 80 + LDA # 0 +_state: STA zp,x KBD_STATE + DEX i + BNE r :_state + + +loop: LDX # 7 ; state + LDA # %01111111 + STA zp KBD_COM_MASK + +loop0: LDA zp KBD_COM_MASK + STA a VIA1_PORTA + + LDY # 4 ; bit + LDA a VIA1_PORTB +loop1: ROR A + PHA s ; [A] + PHP s ; [P,A] + ;; { A = (X * 8 + Y) + TXA i + ASL A + ASL A + ASL A + STY zp 1 + ORA zp 1 + ;; } + + PLP s ; [A] + PHX s ; [X,A] + TAX i + BCS r :_kbd_up + + ;;; begin down +_kbd_down: LDA zp,x KBD_STATE + CMP # 4 + BNE r :_kbd_state_inc + ;; if (KBD_STATE[X] == 4) { + LDA a,x KBD_STATE2 + BNE r :_loop1_resume + ;; if (KBD_STATE2[X] == 0) { + INC a,x KBD_STATE2 + + LDA zp KBD_LAYER + ASL A + ASL A + ASL A + ASL A + ASL A + ASL A ; << 6 + STX zp 1 + ORA zp 1 + TAX i + + LDA a,x :_bin_res/keymap_start + PHY s ; [Y,X,A] + JSR a :kbd_char_draw + PLY s ; [X,A] + + BRA r :_loop1_resume + ;; } + ;; } + +_kbd_state_inc: INC zp,x KBD_STATE + BRA r :_loop1_resume + ;;; end down + + ;;; begin up +_kbd_up: LDA zp,x KBD_STATE + BEQ r :_kbd_up_state2 + +_kbd_state_dec: DEC zp,x KBD_STATE + BRA r :_loop1_resume + +_kbd_up_state2: STZ a,x KBD_STATE2 + ;;; end up + +_loop1_resume: PLX s ; [A] + PLA s ; [] + DEY i + BPL r :loop1 + + SEC i + ROR zp KBD_COM_MASK + DEX i + BPL r :loop0 + + BRA r :loop +;;; end main loop + + +_kbd_char_nonprint: SEC i + SBC # 80 + CMP # 4 ; L0 through L3 + BCC r :_kbd_set_layer + BEQ r :_kbd_backspace ; BACKSPACE + BCS r :_kbd_enter ; ENTER or ??? + +_kbd_jump_return: RTS s + +_kbd_set_layer: AND # %11 + STA zp KBD_LAYER + STA a VIA2_PORTA + RTS s + +_kbd_enter: LDA # ^32 + LDY zp KBD_GLCD_C + BNE r :_kbd_enter_c1 + ;; fallthrough to _kbd_backspace_c2 +_kbd_enter_c2: JSR a :gfont_draw_c2 + JMP a :_kbd_end_of_line ; too long for BRA +_kbd_enter_c1: JSR a :gfont_draw_c1 + JMP a :_kbd_end_of_line ; too long for BRA + +_kbd_backspace: LDA # ^32 + LDY zp KBD_GLCD_C + BNE r :_kbd_backspace_c1 + ;; fallthrough to _kbd_backspace_c2 +_kbd_backspace_c2: JSR a :gfont_draw_c2 + LDA zp KBD_GLCD_Y + CLC i + ADC # 5 + CMP # ^56 + BMI r :_kbd_char_c2_cursor + ;; transitioning to c1 + LDY # 1 + STY zp KBD_GLCD_C + + ;; beginning of line, increment X page + LDA zp KBD_GLCD_X + INC A + AND # %111 + STA zp KBD_GLCD_X + + ORA # %10111000 ; X page + JSR a :glcd_w_rs0_c2 + LDA zp KBD_GLCD_X + ORA # %10111000 ; X page + JSR a :glcd_w_rs0_c1 + + LDA # ^4 + BRA r :_kbd_char_c1_cursor + +_kbd_backspace_c1: JSR a :gfont_draw_c1 + LDA zp KBD_GLCD_Y + CLC i + ADC # 5 + CMP # ^60 + BMI r :_kbd_char_c1_cursor + ;; transitioning to c2 + LDY # 0 + STY zp KBD_GLCD_C + LDA # ^0 + BRA r :_kbd_char_c2_cursor + +;;; begin char_draw (A) +kbd_char_draw: CMP # 80 + BCS r :_kbd_char_nonprint + LDY zp KBD_GLCD_C + BNE r :_kbd_char_c1 + ;; fallthrough to _kbd_char_c2 + +;;; c2: [55,0] + ;; if (KBD_GLCD_C == 0) { +_kbd_char_c2: JSR a :gfont_draw_c2 + + LDA zp KBD_GLCD_Y + SEC i + SBC # 5 + BPL r :_kbd_char_c2_cursor + ;; transitioning to c1 + LDY # 1 + STY zp KBD_GLCD_C + LDA # ^59 + BRA r :_kbd_char_c1_cursor + +_kbd_char_c2_cursor: STA zp KBD_GLCD_Y + ORA # %01000000 ; Y address + JSR a :glcd_w_rs0_c2 + + LDA # ^95 + JSR a :gfont_draw_c2 + + LDA zp KBD_GLCD_Y + ORA # %01000000 ; Y address + JSR a :glcd_w_rs0_c2 + + RTS s + ;; } + +;;; c2: [59,4] + ;; if (KBD_GLCD_C == 1) { +_kbd_char_c1: JSR a :gfont_draw_c1 + + LDA zp KBD_GLCD_Y + SEC i + SBC # 5 + CMP # 4 + BPL r :_kbd_char_c1_cursor + ;; transitioning to c2 +_kbd_end_of_line: LDY # 0 + STY zp KBD_GLCD_C + + ;; end of line, decrement X page + LDA zp KBD_GLCD_X + DEC A + AND # %111 + STA zp KBD_GLCD_X + + ORA # %10111000 ; X page + JSR a :glcd_w_rs0_c2 + LDA zp KBD_GLCD_X + ORA # %10111000 ; X page + JSR a :glcd_w_rs0_c1 + + LDA # ^55 + BRA r :_kbd_char_c2_cursor + +_kbd_char_c1_cursor: STA zp KBD_GLCD_Y + ORA # %01000000 ; Y address + JSR a :glcd_w_rs0_c1 + + LDA # ^95 + JSR a :gfont_draw_c1 + + LDA zp KBD_GLCD_Y + ORA # %01000000 ; Y address + JSR a :glcd_w_rs0_c1 + + RTS s + ;; } +;;; end char_draw diff --git a/lcd.asm b/lcd.asm new file mode 100644 index 0000000..cd99853 --- /dev/null +++ b/lcd.asm @@ -0,0 +1,130 @@ + ;; Set pins 0-7 on Port B to Output + LDA # FF + STA a 8002 + + ;; Set pins 0-2 on Port A to Output + LDA # 7 + STA a 8003 + + ;; 00111000 set 8-bit mode, 2-line display, 5x8 font + LDA # 38 + STA a 8000 + LDA # 0 + STA a 8001 ; clear RS|RW|E + LDA # 1 + STA a 8001 ; set E + LDA # 0 + STA a 8001 ; clear RS|RW|E + + ;; 00001110 display on; cursor on; blink off + LDA # E + STA a 8000 + LDA # 0 + STA a 8001 ; clear RS|RW|E + LDA # 1 + STA a 8001 ; set E + LDA # 0 + STA a 8001 ; clear RS|RW|E + + ;; 00000001 Clear Display: + LDA # 1 + STA a 8000 + LDA # 0 + STA a 8001 ; clear RS|RW|E + LDA # 1 + STA a 8001 ; set E + LDA # 0 + STA a 8001 ; clear RS|RW|E + + ;; 00000110 Entry Mode Set: increment and shift cursor; don't shift display + LDA # 6 + STA a 8000 + LDA # 0 + STA a 8001 ; clear RS|RW|E + LDA # 1 + STA a 8001 ; set E + LDA # 0 + STA a 8001 ; clear RS|RW|E + + ;; l + LDA # 6C + STA a 8000 + LDA # 2 + STA a 8001 ; set RS; clear RW|E + LDA # 3 + STA a 8001 ; set RS|E + LDA # 2 + STA a 8001 ; set RS; clear RW|E + + ;; o + LDA # 6F + STA a 8000 + LDA # 2 + STA a 8001 ; set RS; clear RW|E + LDA # 3 + STA a 8001 ; set RS|E + LDA # 2 + STA a 8001 ; set RS; clear RW|E + + ;; v + LDA # 76 + STA a 8000 + LDA # 2 + STA a 8001 ; set RS; clear RW|E + LDA # 3 + STA a 8001 ; set RS|E + LDA # 2 + STA a 8001 ; set RS; clear RW|E + + ;; e + LDA # 65 + STA a 8000 + LDA # 2 + STA a 8001 ; set RS; clear RW|E + LDA # 3 + STA a 8001 ; set RS|E + LDA # 2 + STA a 8001 ; set RS; clear RW|E + + ;; ' ' + LDA # 20 + STA a 8000 + LDA # 2 + STA a 8001 ; set RS; clear RW|E + LDA # 3 + STA a 8001 ; set RS|E + LDA # 2 + STA a 8001 ; set RS; clear RW|E + + ;; a + LDA # 61 + STA a 8000 + LDA # 2 + STA a 8001 ; set RS; clear RW|E + LDA # 3 + STA a 8001 ; set RS|E + LDA # 2 + STA a 8001 ; set RS; clear RW|E + + ;; n + LDA # 6E + STA a 8000 + LDA # 2 + STA a 8001 ; set RS; clear RW|E + LDA # 3 + STA a 8001 ; set RS|E + LDA # 2 + STA a 8001 ; set RS; clear RW|E + + ;; a + LDA # 61 + STA a 8000 + LDA # 2 + STA a 8001 ; set RS; clear RW|E + LDA # 3 + STA a 8001 ; set RS|E + LDA # 2 + STA a 8001 ; set RS; clear RW|E + + +forever: JMP a :forever diff --git a/mul5.asm b/mul5.asm new file mode 100644 index 0000000..0512bbf --- /dev/null +++ b/mul5.asm @@ -0,0 +1,5 @@ + LDA # d15 + STA zp 0 + ASL A + ASL A + ADC zp 0 diff --git a/oled.asm.in b/oled.asm.in new file mode 100644 index 0000000..d076f8a --- /dev/null +++ b/oled.asm.in @@ -0,0 +1,198 @@ +; -*-asm-*- +include(`common.m4') + + BRA r :reset ; RESB + NOP i ; IRQ + + ;; reset stack +reset: LDX # ff + TXS i + + ;; Set pins 0-4 on Port A to Output + LDA # %00011111 + STA a DDRA + + ;; Display ON/OFF: + ;; D7 D6 D5 D4 D3 D2 D1 D0 + ;; 0 0 1 1 1 1 1 D + ;; + LDA # %00111111 + JSR a :lcd-w-rs0-c2 + LDA # %00111111 + JSR a :lcd-w-rs0-c1 + + JSR a :reset-oled + + LDA # 0 ; face address + STA zp 0 + LDX # 1 ; X page + +_face_page: LDA # %01000000 ; Y address + JSR a :lcd-w-rs0-c2 + + TXA i + ORA # %10111000 ; X page + JSR a :lcd-w-rs0-c2 + TXA i + ORA # %10111000 ; X page + JSR a :lcd-w-rs0-c1 + + PHX s + LDY # 17 ; Y address + LDX zp 0 +_face_fill: LDA a,x :_bin_face_start + JSR a :lcd-w-rs1-c2 + + TYA i + CLC i + ADC # 28 + ORA # %01000000 ; Y address + JSR a :lcd-w-rs0-c1 + + LDA a,x :_bin_face_start + JSR a :lcd-w-rs1-c1 + + INX i + STX zp 0 + + DEY i + CPY # 0 + BPL r :_face_fill ; BGE 0 + + PLX s + INX i + CPX # 7 + BNE r :_face_page + +stop: JMP a :stop + + +reset-oled: LDY # 00 + + LDA # %01000000 ; Y address + JSR a :lcd-w-rs0-c2 + +_next_page: TYA i + ORA # %10111000 ; X page + JSR a :lcd-w-rs0-c2 + + TYA i + ORA # %10111000 ; X page + JSR a :lcd-w-rs0-c1 + + LDX # 40 +_fill_page: LDA # 00 + JSR a :lcd-w-rs1-c2 + + TXA i + SEC i + SBC # 1 + ORA # %01000000 ; Y address + JSR a :lcd-w-rs0-c1 + + LDA # 00 + JSR a :lcd-w-rs1-c1 + DEX i + BNE r :_fill_page + + INY i + CPY # 8 + BNE r :_next_page + + RTS s + + ;; write "instruction" +lcd-w-rs0-c2: JSR a :lcd-wait-c2 + + STA a PORTB + LDA # hh(G_C2) + STA a PORTA + LDA # hh(G_C2|G_E) + STA a PORTA + LDA # hh(G_C2) + STA a PORTA + + RTS s + +lcd-w-rs0-c1: JSR a :lcd-wait-c1 + + STA a PORTB + LDA # hh(G_C1) + STA a PORTA + LDA # hh(G_C1|G_E) + STA a PORTA + LDA # hh(G_C1) + STA a PORTA + + RTS s + + ;; write "data" to lcd +lcd-w-rs1-c2: JSR a :lcd-wait-c2 + + STA a PORTB + LDA # hh(G_RS|G_C2) + STA a PORTA + LDA # hh(G_RS|G_C2|G_E) + STA a PORTA + LDA # hh(G_RS|G_C2) + STA a PORTA + + RTS s + +lcd-w-rs1-c1: JSR a :lcd-wait-c1 + + STA a PORTB + LDA # hh(G_RS|G_C1) + STA a PORTA + LDA # hh(G_RS|G_C1|G_E) + STA a PORTA + LDA # hh(G_RS|G_C1) + STA a PORTA + + RTS s + + ;; wait BF +lcd-wait-c2: PHA s + + LDA # %00000000 ;; Set pins 0-7 on Port B to Input + STA a DDRB + +_lcd_wait-c2: LDA # hh(G_RW|G_C2) + STA a PORTA + LDA # hh(G_RW|G_C2|G_E) + STA a PORTA + LDA a PORTB + AND # %10000000 + BNE r :_lcd_wait-c2 + + LDA # hh(G_RW|G_C2) + STA a PORTA + + LDA # %11111111 ;; Set pins 0-7 on Port B to Output + STA a DDRB + + PLA s + RTS s + + ;; wait BF +lcd-wait-c1: PHA s + + LDA # %00000000 ;; Set pins 0-7 on Port B to Input + STA a DDRB + +_lcd_wait-c1: LDA # hh(G_RW|G_C1) + STA a PORTA + LDA # hh(G_RW|G_C1|G_E) + STA a PORTA + LDA a PORTB + AND # %10000000 + BNE r :_lcd_wait-c1 + + LDA # hh(G_RW|G_C1) + STA a PORTA + + LDA # %11111111 ;; Set pins 0-7 on Port B to Output + STA a DDRB + + PLA s + RTS s diff --git a/res/keymap.txt b/res/keymap.txt new file mode 100644 index 0000000..37196b7 --- /dev/null +++ b/res/keymap.txt @@ -0,0 +1,67 @@ + pb0 pb1 pb2 pb3 pb4 +pa3 1 2 3 4 5 +pa2 q w e r t +pa1 a s d f g +pa0 z x c v b + +pa4 6 7 8 9 0 +pa5 y u i o p +pa6 h j k l ; +pa7 n m , . _ + + +pa: 0111 1111 +10000 b +01000 v +00100 c +00010 x +00001 z + +pa: 1011 1111 +10000 g +01000 f +00100 d +00010 s +00001 a + +pa: 1101 1111 +10000 t +01000 r +00100 e +00010 w +00001 q + +pa: 1110 1111 +10000 5 +01000 4 +00100 3 +00010 2 +00001 1 + +pa: 1111 0111 +10000 0 +01000 9 +00100 8 +00010 7 +00001 6 + +pa: 1111 1011 +10000 p +01000 o +00100 i +00010 u +00001 y + +pa: 1111 1101 +10000 ; +01000 l +00100 k +00010 j +00001 h + +pa: 1111 1110 +10000 _ +01000 . +00100 , +00010 m +00001 n diff --git a/shift.asm.in b/shift.asm.in new file mode 100644 index 0000000..f0345bc --- /dev/null +++ b/shift.asm.in @@ -0,0 +1,95 @@ +; -*-asm-*- +include(`common.m4') + + BRA r :reset ; RESB + BRA r :irq ; IRQB + +irq: PHA s + LDA a %10000000 + STA a IFR + PLA s + RTI s + + ;; reset stack +reset: LDX # ff + TXS i + + ;; xxxSSSxx + LDA # hh(ACR_SR_OUT_PHI2) + STA a ACR + + LDA # %10000000 + STA a PORTA + + LDA # %10000000 + STA a DDRA + + LDA # %01111111 + STA a IER + + LDA # %10000100 + STA a IER + + ;; R T FEN SHD TM RM PM RAM + ;; 1 1 1 0 0 0 0 0 + LDX # %11100000 ; write configuration + ;; IR ST PE L B3 B2 B1 B0 + ;; 0 0 0 0 0 0 0 1 ; 115200 + LDY # %00000001 + JSR a :spi16 + + ;; R T FEN SHD TM RM PM RAM + ;; 1 1 1 0 0 0 0 0 + LDX # %11100000 ; write configuration + ;; IR ST PE L B3 B2 B1 B0 + ;; 0 0 0 0 0 0 0 1 ; 115200 + LDY # %00000001 + JSR a :spi16 + + ;; R T FEN SHD TM RM PM RAM + ;; 1 1 1 0 0 0 0 0 + LDX # %01000000 ; read configuration + ;; IR ST PE L B3 B2 B1 B0 + ;; 0 0 0 0 0 0 0 1 ; 115200 + LDY # %00000000 + JSR a :spi16 + + ;; R T FEN SHD TM RM PM RAM + ;; 1 1 1 0 0 0 0 0 + LDX # %01000000 ; read configuration + ;; IR ST PE L B3 B2 B1 B0 + ;; 0 0 0 0 0 0 0 1 ; 115200 + LDY # %00000000 + JSR a :spi16 + + LDX # %00000000 ; read data + LDY # %00000000 + JSR a :spi16 + + LDX # %10000000 ; write data + LDY # ca + JSR a :spi16 + + LDX # %10000010 ; write data + LDY # ca + JSR a :spi16 + + +forever: BRA r :forever + +spi16: CLI i + + LDA # %00000000 + STA a PORTA + + STX a SR + WAI i + STY a SR + WAI i + + LDA # %10000000 + STA a PORTA + + SEI i + + RTS s diff --git a/shift2-old.asm.in b/shift2-old.asm.in new file mode 100644 index 0000000..52703ab --- /dev/null +++ b/shift2-old.asm.in @@ -0,0 +1,74 @@ +; -*-asm-*- +include(`common.m4') + + BRA r :reset ; RESB + BRA r :irq ; IRQB + +irq: PHA s + LDA a %10000000 + STA a IFR + PLA s + RTI s + + ;; reset stack +reset: SEI i + + LDX # ff + TXS i + + ;; xxxSSSxx + LDA # hh(ACR_SR_OUT_PHI2) + STA a ACR + + LDA # %10000000 + STA a PORTA + + ;; CS SCLK DO x x x x x + LDA # %11100000 + STA a DDRA + + ;; LDA # %01111111 + ;; STA a IER + + ;; LDA # %10000100 + ;; STA a IER + + ;; low byte + LDX # %11000000 ; write conf + LDY # %00000001 + JSR a :spi16 + + LDX # %10000000 ; write data + LDY # ca + JSR a :spi16 + +forever: BRA r :forever + + ;; CS low +spi16: LDA # %00000000 + STA a PORTA + + STX zp 1 + STY zp 2 + + LDY # 2 +_spi_next: LDX # 8 + CLC i + ASL zp,y 0 + LDA # %00000000 ; clear DO + BCC r :_spi_z + ORA # %00100000 ; set DO +_spi_z: STA a PORTA + NOP i + ORA # %01000000 ; set SCLK + STA a PORTA + AND # %10111111 ; clear SCLK + STA a PORTA + DEX i + BNE r :_spi_next + DEY i + BNE r :_spi_next + ;; CS high + LDA # %10000000 + STA a PORTA + RTS s diff --git a/shift2.asm b/shift2.asm new file mode 100644 index 0000000..7ab417a --- /dev/null +++ b/shift2.asm @@ -0,0 +1,74 @@ +; -*-asm-*- + + + BRA r :reset ; RESB + BRA r :irq ; IRQB + +irq: PHA s + LDA a %10000000 + STA a 800d + PLA s + RTI s + + ;; reset stack +reset: SEI i + + LDX # ff + TXS i + + ;; xxxSSSxx + LDA # 18 + STA a 800b + + LDA # %10000000 + STA a 8001 + + ;; CS SCLK DO x x x x x + LDA # %11100000 + STA a 8003 + + ;; LDA # %01111111 + ;; STA a 800e + + ;; LDA # %10000100 + ;; STA a 800e + + ;; low byte + LDX # %11000000 ; write conf + LDY # %00000001 + JSR a :spi16 + + LDX # %10000000 ; write data + LDY # 6c + JSR a :spi16 + +forever: BRA r :forever + + ;; CS low +spi16: LDA # %00000000 + STA a 8001 + + STX zp 2 + STY zp 1 + + LDX # 2 +_spi_next: LDY # 8 +_spi_8: CLC i + ASL zp,x 0 + LDA # %00000000 ; clear DO + BCC r :_spi_z + ORA # %00100000 ; set DO +_spi_z: STA a 8001 + NOP i + ORA # %01000000 ; set SCLK + STA a 8001 + AND # %10111111 ; clear SCLK + STA a 8001 + DEY i + BNE r :_spi_8 + DEX i + BNE r :_spi_next + ;; CS high + LDA # %10000000 + STA a 8001 + RTS s diff --git a/shift3.asm.in b/shift3.asm.in new file mode 100644 index 0000000..5441314 --- /dev/null +++ b/shift3.asm.in @@ -0,0 +1,79 @@ +; -*-asm-*- +include(`common.m4') + + BRA r :reset ; RESB + BRA r :irq ; IRQB + +irq: RTI s + + ;; reset stack +reset: SEI i + + LDX # ff + TXS i + + ;; CS high, SCLK low + LDA # hh(M_CS) + STA a PORTA + + LDA # hh(M_DDRA_MASK) + STA a DDRA + + LDX # hh(M_CFGH|M_CFGH_FENB) + LDY # hh(M_CFGL_BAUD_115200) + JSR a :spi16 + + ;; read data +tryagain: LDX # hh(M_R_DATA) + LDY # hh(M_R_DATA) + JSR a :spi16 + + LDA zp 4 + BPL r :tryagain ; BPL = if the leftmost bit is 0, go here + + ;; write data + LDX # hh(M_W_DATAH) + LDY zp 3 + JSR a :spi16 + + BRA r :tryagain + + ;; CS low, SCLK low +spi16: LDA # %00000000 + STA a PORTA + + STX zp 2 + STY zp 1 + ;; SPI output + STZ zp 4 + STZ zp 3 + + LDX # 2 +_spi_next: LDY # 8 + STY zp 0 +_spi_8: ASL zp,x 0 + LDA # 0 ; preclear MOSI + BCC r :_spi_zout + ORA # hh(M_DIN) ; set MOSI +_spi_zout: STA a PORTA + + ORA # hh(M_SCLK) ; set SCLK + STA a PORTA + + LDY a PORTA ; DOUT on bit 7 + CLC i ; preclear MISO + BPL r :_spi_zin ; + SEC i ; set MISO +_spi_zin: ROL zp,x 2 + + AND # hh(~M_SCLK & 0xff) ; clear SCLK + STA a PORTA + + DEC zp 0 + BNE r :_spi_8 + DEX i + BNE r :_spi_next + ;; CS high, SCLK low + LDA # hh(M_CS) + STA a PORTA + RTS s diff --git a/test.asm b/test.asm new file mode 100644 index 0000000..cd350b9 --- /dev/null +++ b/test.asm @@ -0,0 +1,5 @@ + LDX # ff + LDX # 00 + LDX # 7f + LDX # 80 + LDX # fe diff --git a/timer.asm.in b/timer.asm.in index be5645d..56c389c 100644 --- a/timer.asm.in +++ b/timer.asm.in @@ -17,11 +17,15 @@ irq: PHA s ;;; end irq -reset: LDX # ff +reset: SEI i + LDX # ff TXS i - LDA # %10000000 ;; Set pins 0-7 on Port B to Output - STA a DDRA + LDA # %00000001 ;; Set pins 0-7 on Port B to Output + STA a DDRB + + LDA # %00000001 + STA a PORTB JSR a :continuous @@ -30,9 +34,9 @@ count: LDA # 25 loop: LDA zp ticks_ BPL r :loop - LDA # %10000000 - EOR a PORTA - STA a PORTA + LDA # %00000001 + EOR a PORTB + STA a PORTB BRA r :count diff --git a/tools/Bm437_EverexME_5x8.otb b/tools/Bm437_EverexME_5x8.otb new file mode 100644 index 0000000..d4f3672 Binary files /dev/null and b/tools/Bm437_EverexME_5x8.otb differ diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000..5891d9a --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,20 @@ +CFLAGS = -Wall -Wextra -Werror -Wno-unused-parameter -pedantic -ggdb +CFLAGS += $(shell pkg-config --cflags freetype2) +#CFLAGS += $(shell pkg-config --cflags libutf8proc) +LDFLAGS = $(shell pkg-config --libs freetype2) +#LDFLAGS = $(shell pkg-config --libs libutf8proc) + +all: otb-convert + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +%: %.o + $(CC) $< -o $@ + +otb-convert: %.o + $(CC) $(LDFLAGS) $< -o $@ + + + +.SUFFIXES: diff --git a/tools/keymap.py b/tools/keymap.py new file mode 100644 index 0000000..12f4a6c --- /dev/null +++ b/tools/keymap.py @@ -0,0 +1,79 @@ +L0 = 128 +L1 = 129 +L2 = 130 +L3 = 131 +BKSPC = 132 +ENTER = 133 + +keymap = [ + [ + [ "q", "w", "f", "p", "b", "j", "l", "u", "y", ";"], + [ "a", "r", "s", "t", "g", "k", "n", "e", "i", "o"], + [ 0, "x", "c", "d", "v", "m", "h", "z", 0, 0], + [ L0, L1, L2, L3, " ",BKSPC, 0, 0, 0,ENTER], + ], + [ + [ "Q", "W", "F", "P", "B", "J", "L", "U", "Y", ":"], + [ "A", "R", "S", "T", "G", "K", "N", "E", "I", "O"], + [ 0, "X", "C", "D", "V", "M", "H", "Z", 0, 0], + [ L0, L1, L2, L3, " ",BKSPC, 0, 0, 0,ENTER], + ], + [ + [ "'", "~", "=", "{", "@", "%", "}", "_", "*", "\""], + [ ",", "\\", "+", "(", "<", ">", ")", "-", "/", "."], + [ "`", "?", "#", "[", "|", "&", "]", "$", "!", "^"], + [ L0, L1, L2, L3, " ",BKSPC, 0, 0, 0,ENTER], + ], + [ + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ L0, L1, L2, L3, " ",BKSPC, 0, 0, 0,ENTER], + ], +] + +# qwerty_keymap = [ +# ["z", "x", "c", "v", "b"], +# ["a", "s", "d", "f", "g"], +# ["q", "w", "e", "r", "t"], +# ["1", "2", "3", "4", "5"], +# ["6", "7", "8", "9", "0"], +# ["y", "u", "i", "o", "p"], +# ["h", "j", "k", "l", ";"], +# ["n", "m", ",", ".", " "], +# ] + + +def visual_to_scancode(table): + assert len(table) == 4 + assert all(len(row) == 10 for row in table) + + yield table[3][0:5] + yield table[2][0:5] + yield table[1][0:5] + yield table[0][0:5] + yield table[0][5:10] + yield table[1][5:10] + yield table[2][5:10] + yield table[3][5:10] + + +def keymap_table(): + for layer in keymap: + for state in visual_to_scancode(layer): + for key in reversed(state): + if type(key) is str: + code = ord(key) + assert code < 128 + yield code + elif type(key) is int: + yield key + else: + raise TypeError(key) + for _ in range(8 - len(state)): + yield ord('?') + + +import sys +with open(sys.argv[1], 'wb') as f: + f.write(bytes(keymap_table())) diff --git a/tools/otb-convert.c b/tools/otb-convert.c new file mode 100644 index 0000000..0c0d127 --- /dev/null +++ b/tools/otb-convert.c @@ -0,0 +1,102 @@ +#include +#include + +#include +#include FT_FREETYPE_H + +int load_char(FT_Face face, FT_ULong char_code, unsigned char * buf) +{ + FT_Error error; + FT_UInt glyph_index = FT_Get_Char_Index(face, char_code); + + error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); + if (error) { + printf("FT_Load_Glyph %s\n", FT_Error_String(error)); + return 0; + } + + assert(face->glyph->format == FT_GLYPH_FORMAT_BITMAP); + assert(face->glyph->bitmap.num_grays == 2); + assert(face->glyph->bitmap.pitch == 1); + if (face->glyph->bitmap.width != 5) + fprintf(stderr, "%ld\n", char_code); + assert(face->glyph->bitmap.width == 5); + assert(face->glyph->bitmap.rows == 8); + //fprintf(stderr, "%ld %d\n", char_code, face->glyph->bitmap.rows); + + for (int x = 0; x < 8; x++) buf[x] = 0; + + for (int y = 0; y < (int)face->glyph->bitmap.rows; y++) { + char row = face->glyph->bitmap.buffer[y]; + for (int x = 0; x < 5; x++) { + int bit = (row >> (7 - x)) & 1; + buf[x] |= (bit << (7 - y)); + } + } + + /* + for (int y = 0; y < (int)face->glyph->bitmap.rows; y++) { + char row = face->glyph->bitmap.buffer[y]; + unsigned char row_out = 0; + for (int x = 0; x < 8; x++) { + int bit; + if (x < (int)face->glyph->bitmap.width) { + bit = (row >> (7 - x)) & 1; + } else { + bit = 0; + } + //fprintf(stderr, bit ? "█" : " "); + row_out |= (bit << x); + } + //fprintf(stderr, "\n"); + buf[y] = row_out; + } + */ + + //return face->glyph->bitmap.rows; + return 8; +} + +int main(int argc, char *argv[]) +{ + FT_Library library; + FT_Face face; + FT_Error error; + + if (argc < 2) { + fprintf(stderr, "argc"); + return -1; + } + + error = FT_Init_FreeType(&library); + if (error) { + fprintf(stderr, "FT_Init_FreeType\n"); + return -1; + } + + error = FT_New_Face(library, argv[1], 0, &face); + if (error) { + fprintf(stderr, "FT_New_Face\n"); + return -1; + } + + error = FT_Select_Size(face, 0); + if (error) { + fprintf(stderr, "FT_Select_Size: %s %d\n", FT_Error_String(error), error); + return -1; + } + +#define CHARS (128) + + unsigned char buf[CHARS * face->available_sizes[0].height]; + int ret; + unsigned char * bufi = buf; + for (unsigned long c = 0; c < CHARS; c++) { + ret = load_char(face, c, bufi); + if (ret == 0) + return -1; + bufi += ret; + } + + fwrite(buf, (sizeof (buf[0])), (sizeof (buf)) / (sizeof (buf[0])), stdout); +} diff --git a/tools/term.c b/tools/term.c new file mode 100644 index 0000000..450d6d5 --- /dev/null +++ b/tools/term.c @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static int fd = -1; + +void int_handler(int dummy) { + write(STDERR_FILENO, "sigint\n", 7); + + if (fd != -1) + close(fd); + + exit(1); +} + +void +set_attrs(int fd) +{ + struct termios t; + int attr = tcgetattr(fd, &t); + assert (attr != -1); + + cfsetospeed(&t, B115200); + cfsetispeed(&t, B115200); + + t.c_cflag = (t.c_cflag & ~CSIZE) | CS8; // 8-bit chars + t.c_lflag = 0; // no signaling chars, no echo, no canonical processing + t.c_oflag = 0; // no remapping, no delays + t.c_cc[VMIN] = 1; // read doesn't block + t.c_cc[VTIME] = 0; // no timeout + + // convert break to null byte, no CR to NL translation, + // no NL to CR translation, don't mark parity errors or breaks + // no input parity check, don't strip high bit off, + // no XON/XOFF software flow control + t.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | + INLCR | PARMRK | INPCK | ISTRIP | IXOFF | IXON | IXANY); + + t.c_cflag |= (CLOCAL | CREAD); // ignore modem controls, enable reading + t.c_cflag &= ~(PARENB | PARODD); // shut off parity + t.c_cflag &= ~CSTOPB; // one stop bit + t.c_cflag |= CRTSCTS; // enable CTS/RTS + + int ret = tcsetattr(fd, TCSANOW, &t); + assert (ret != -1); +} + +ssize_t +write_block(int fd, char * buf, size_t len) +{ + ssize_t wret, rret; + + size_t out_len = 0; + + char in_buf[len]; + memset(in_buf, 0xea, len); + +#define BLOCK_SIZE 8 + + for (unsigned int i = 0; i < (len / BLOCK_SIZE); i++) { + wret = write(fd, &buf[BLOCK_SIZE * i], BLOCK_SIZE); + assert (wret == BLOCK_SIZE); + int tret = tcdrain(fd); + assert (tret != -1); + + //printf("%x\n", out_buf[BLOCK_SIZE * i] & 0xff, rret); + + size_t block = 0; + while (block != BLOCK_SIZE) { + rret = read(fd, &in_buf[(BLOCK_SIZE * i) + block], BLOCK_SIZE - block); + assert (rret != -1); + block += rret; + } + //printf("%x %x %ld\n", out_buf[BLOCK_SIZE * i] & 0xff, in_buf[BLOCK_SIZE * i] & 0xff, rret); + assert (block == BLOCK_SIZE); + + out_len += block; + + write(STDERR_FILENO, ".", 1); + fsync(STDERR_FILENO); + } + + size_t rem = len % BLOCK_SIZE; + if (rem) { + wret = write(fd, &buf[len - rem], rem); + assert (wret != -1); + assert ((size_t)wret == rem); + int tret = tcdrain(fd); + assert (tret != -1); + + size_t block = 0; + while (block != rem) { + rret = read(fd, &in_buf[len - rem + block], rem - block); + assert (rret != -1); + block += rret; + } + //printf("%x %x %ld\n", buf[BLOCK_SIZE * i] & 0xff, in_buf[BLOCK_SIZE * i] & 0xff, rret); + assert (block == rem); + + out_len += block; + + write(STDERR_FILENO, ".", 1); + fsync(STDERR_FILENO); + } + + write(STDERR_FILENO, "\n", 1); + + //int cmp = memcmp(buf, in_buf, len); + for (unsigned int bx = 0; bx < len; bx++) { + if (buf[bx] != in_buf[bx]) { + fprintf(stderr, "buf[%d] != in_buf[%d]\n", bx, bx); + fprintf(stderr, "%02x != %02x\n", buf[bx], in_buf[bx]); + } + } + + return out_len; +} + + +void +write_header(int fd, size_t len, size_t addr) +{ + assert (addr <= 0xffff); + assert (len <= 255); + + fprintf(stderr, "len %ld addr %lx\n", len, addr & 0xffff); + + char out_buf[3] = { + len & 0xff, + (addr >> 0) & 0xff, + (addr >> 8) & 0xff, + }; + ssize_t wret = write(fd, out_buf, 3); + assert (wret != -1); + + size_t hdr_len = len == 0 ? 2 : 3; + char in_buf[3]; + size_t offset = 0; + ssize_t rret; + while (offset != hdr_len) { + rret = read(fd, &in_buf[offset], hdr_len - offset); + assert (rret != -1); + offset += rret; + } + + assert (offset == hdr_len); + int cmp = memcmp(in_buf, "LDR", hdr_len); + assert (cmp == 0); +} + +static char read_buf[0x8000]; + + +int main(int argc, char *argv[]) +{ + signal(SIGINT, int_handler); + + int tfd = open("/dev/ttyUSB0", O_RDWR | O_SYNC | O_NOCTTY); + assert (tfd != -1); + + set_attrs(tfd); + + int tret = tcflush(tfd, TCIOFLUSH); + assert (tret != -1); + + assert (argc > 1); + fprintf(stderr, "%s\n", argv[1]); + + int ffd = open(argv[1], O_RDONLY); + ssize_t rret = read(ffd, read_buf, 0x8000); + assert (rret != -1 && rret > 0 && rret <= 0x8000); + + size_t offset = 0; + size_t base_address = 0x200; + + while (rret - offset > 0) { + size_t block_len = rret - offset >= 255 ? 255 : rret - offset; + write_header(tfd, block_len, base_address + offset); + ssize_t block_ret = write_block(tfd, &read_buf[offset], block_len); + assert (block_ret != -1); + assert ((size_t)block_ret == block_len); + offset += block_ret; + } + + fprintf(stderr, "jump %lx\n", base_address & 0xffff); + write_header(tfd, 0, base_address); + + close(fd); +} + +// stty -F /dev/ttyUSB0 115200 -icrnl -imaxbel -opost -onlcr -isig -echo -icanon -ixon diff --git a/wink.asm.in b/wink.asm.in index 2de5fc0..567760f 100644 --- a/wink.asm.in +++ b/wink.asm.in @@ -42,7 +42,7 @@ reset: LDX # ff ;; Set DDRAM Address: ;; D7 D6 D5 D4 D3 D2 D1 D0 ;; 1 A6 A5 A4 A3 A2 A1 A0 - LDA # hh(L_DDRAM|0) + LDA # hh(C_DDRAM|0) JSR a :lcd-w-rs0 ;; Write Data: @@ -60,7 +60,7 @@ reset: LDX # ff ;; Set CGRAM Address: ;; D7 D6 D5 D4 D3 D2 D1 D0 ;; 0 1 AC5 AC4 AC3 AC2 AC1 AC0 - LDA # hh(L_CGRAM|0) + LDA # hh(C_CGRAM|0) JSR a :lcd-w-rs0 ;; data is at e000 @@ -97,7 +97,7 @@ loop: LDA (zp),y 00 ;; Set CGRAM Address ;; D7 D6 D5 D4 D3 D2 D1 D0 ;; 0 1 AC5 AC4 AC3 AC2 AC1 AC0 -loop2: LDA # hh(L_CGRAM|9) +loop2: LDA # hh(C_CGRAM|9) JSR a :lcd-w-rs0 ;; Write Data to CGRAM @@ -109,7 +109,7 @@ loop2: LDA # hh(L_CGRAM|9) ;; Set CGRAM Address ;; D7 D6 D5 D4 D3 D2 D1 D0 ;; 0 1 AC5 AC4 AC3 AC2 AC1 AC0 - LDA # hh(L_CGRAM|9) + LDA # hh(C_CGRAM|9) JSR a :lcd-w-rs0 ;; Write Data to CGRAM @@ -129,7 +129,7 @@ lcd-w-rs0: JSR a :lcd-wait STA a PORTB LDA # 0 STA a PORTA - LDA # hh(L_E) + LDA # hh(C_E) STA a PORTA LDA # 0 STA a PORTA @@ -139,11 +139,11 @@ lcd-w-rs0: JSR a :lcd-wait lcd-w-rs1: JSR a :lcd-wait STA a PORTB - LDA # hh(L_RS) + LDA # hh(C_RS) STA a PORTA - LDA # hh(L_RS|L_E) + LDA # hh(C_RS|C_E) STA a PORTA - LDA # hh(L_RS) + LDA # hh(C_RS) STA a PORTA RTS s @@ -153,15 +153,15 @@ lcd-wait: PHA s LDA # %00000000 ;; Set pins 0-7 on Port B to Input STA a DDRB -_lcd_wait: LDA # hh(L_RW) +_lcd_wait: LDA # hh(C_RW) STA a PORTA - LDA # hh(L_E|L_RW) + LDA # hh(C_E|C_RW) STA a PORTA LDA a PORTB AND # %10000000 BNE r :_lcd_wait - LDA # hh(L_RW) + LDA # hh(C_RW) STA a PORTA LDA # %11111111 ;; Set pins 0-7 on Port B to Output