eris2010

Documentation: http://frombelow.net/projects/eris2010/
Clone: git clone https://git.frombelow.net/eris2010.git
Log | Files | Refs | Submodules | README | LICENSE

commit e43c0ba9a8c944f2d62ec4358a198f8be363efd5
parent 82c47766dfd4fd7d1a2490220735a7e38ee58777
Author: Gerd Beuster <gerd@frombelow.net>
Date:   Sun, 27 Dec 2020 13:22:01 +0100

Changed bus logic to support up to 4 I/O devices

Diffstat:
Mdoc/Documentation.txt | 18+++++++++++++++---
Mhw/bus_logic/BUS_LOGIC.PLD | 73+++++++++++++++++++++++++++++++++++--------------------------------------
Mmisc/write_default_files.sh | 12+++++++++++-
Mroms/Makefile.common | 23++++++++++++++++++++---
Droms/boot/ansi.asm | 281-------------------------------------------------------------------------------
Droms/boot/ansi.inc | 59-----------------------------------------------------------
Mroms/boot/boot.asm | 61+++++++++++++++++++++----------------------------------------
Mroms/boot/boot.inc | 59+++++++++++++++++++++++++++++++++++++++--------------------
Aroms/boot/ds.asm | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aroms/boot/ds.inc | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mroms/boot/io.asm | 170+++++++++++++++++++++++++++++++++++--------------------------------------------
Mroms/boot/io.inc | 25++++++++++++++-----------
Mroms/boot/lfsr.asm | 45++++++++++++++++++++++++++-------------------
Aroms/boot/sd.asm | 269+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aroms/boot/sd.inc | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Droms/boot/sd_card.asm | 266-------------------------------------------------------------------------------
Droms/boot/sd_card.inc | 48------------------------------------------------
Mroms/boot/spi.asm | 75++++++++++++++++++++++++++++++++++++++++-----------------------------------
Droms/boot/stack.asm | 72------------------------------------------------------------------------
Droms/boot/stack.inc | 77-----------------------------------------------------------------------------
Aroms/boot/term.asm | 260+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aroms/boot/term.inc | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msw/10print/10print.asm | 32++++++++++----------------------
Msw/ansi_test/ansi_test.asm | 170++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msw/interrupts/interrupts.asm | 2+-
Msw/load_from_card/load_from_card.asm | 148+++++++++++++++++++++++++++++++++++--------------------------------------------
Msw/serial_line_echo/serial_line_echo.asm | 18++++++------------
Msw/stack_test/stack_test.asm | 176+++++++++++++++++++++++++++++++++++++------------------------------------------
Msw/ttt/README.txt | 6++----
Msw/ttt/board.asm | 30+++++++++++++++---------------
Msw/ttt/board_test.asm | 4++--
Msw/ttt/computer_player.asm | 52++++++++++++++++++++++++++--------------------------
Msw/ttt/computer_player_test.asm | 138++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msw/ttt/human_player.asm | 18+++++++++---------
Msw/ttt/ttt.asm | 67+++++++++++++++++++++++--------------------------------------------
Msw/via_test/via_test.asm | 36++++++++++++++----------------------
Mtools/boot.py | 2+-
Mtools/gfs.py | 4++--
38 files changed, 1504 insertions(+), 1560 deletions(-)

diff --git a/doc/Documentation.txt b/doc/Documentation.txt @@ -1,4 +1,4 @@ -* GATE 2010 - An 8-Bit Computer +* Eris 2010 - An 8-Bit Computer ** Main Components @@ -6,7 +6,7 @@ The computer is based on a 65C02 running at 1 Mhz with 32K RAM (AS6C62256-55PCN) and 8 K EEPROM (AT28C64B-15PU). A W65C51N ACAI provides a serial communication interface. Bus logic is provided by a ATF16V8B EEPLD. The reset logic is based on a NE555 in a monostable -configuration (with a little help (an inverter of the AFT16V8B). +configuration with a little help (an inverter on the AFT16V8B). See hw/bom.ods for details of the components. (This list also contains components not used in the current design.) @@ -138,7 +138,7 @@ for examples. *** gfs.py Program for formatting, listing, and writing SD card in a format -readable by GATE 2010. +readable by Eris 2010. *** boot.py @@ -178,9 +178,21 @@ replaced by a NE555 configured as a monostable multivibrator. ** TODOs +*** Wire interrupt lines + +- To VIA(s) and ACIA(s) +- Add reset button + +*** Reset Logic + +- Add switch or jumper to enable/disable connection between DTR and reset +- Change indicator LED to off-on-reset +- Reduce delay in NE555 reset circuit + *** Write library functions - Multiplication and division - CRC generator *** Design PCB + diff --git a/hw/bus_logic/BUS_LOGIC.PLD b/hw/bus_logic/BUS_LOGIC.PLD @@ -22,10 +22,10 @@ pin 8 = reset_in; /* Reset logic output */ pin 9 = phi; /* cpu_PHI2 */ pin 12 = o0; /* eeprom_#ce */ pin 13 = o1; /* ram_#oe */ -pin 14 = o2; /* acai_#cs0 */ +pin 14 = o2; /* I/O Devices */ pin 15 = o3; /* ram_#ce */ -pin 16 = o4; /* ce (not assigned) */ -pin 17 = o5; /* ce (not assigned) */ +pin 16 = o4; /* I/O Devices */ +pin 17 = o5; /* I/O Devices */ pin 18 = o6; /* #we */ pin 19 = o7; /* cpu_RESB */ @@ -39,30 +39,43 @@ o0 = (!i0 # !i1 # !i2); /* RAM (32k) Address range: 0x0000 - 0x7fff Bit pattern: 0b0............... - */ - -/* See below */ - -/* ACIA (1k) - Address range: 0xdc00 - 0xdfff - Bit pattern: 0b110111.......... -*/ - -o2 = (!i0 # !i1 # i2 # !i3 # !i4 # !i5); -/* VIA (1k) - Address range: 0xd800 - 0xdbff - Bit pattern: 0b110110.......... -*/ + RAM access must happen only in secon half of cycle, therefore + oe#, ce#, and we# are qualified by !phi. + */ -o4 = (!i0 # !i1 # i2 # !i3 # !i4 # i5); +o1 = !phi # !rwb; /* ram_oe# */ +o3 = !phi # i0; /* ram_ce# */ +o6 = !phi # rwb; /* ram_we# */ + +/* In order to drive up to 4 I/O devices from 3 output lines, we + exploit that both the 6522 and the 6551 have two ce lines, of which + one must be logic 1 and the other logic 0. In the table below, + columns ce and #ce indicate which lines should be connected to ce + and #ce of the I/O device given in the row. The third column ensure + that all selections are distinct. Column four and five assign + the I/O devices to input addresses. + + ce #ce i3 i4 + acia0 : o2 & !o4 & !o5 0 0 + via0 : o4 & !o2 & o5 0 1 + acia1 : o5 & !o4 & !o2 1 0 + via1 : o4 & !o5 & o2 1 1 + + We place the I/O devices right below the ROM, + i.e. i0 i1 i2 == 0b110, resulting in the + following address mapping: + + acia0 : 0b11000........... = 0xc000 .. 0xc7ff + via0 : 0b11001........... = 0xc800 .. 0xcfff + acia1 : 0b11010........... = 0xd000 .. 0xd7ff + via1 : 0b11011........... = 0xd800 .. 0xdfff -/* TBA (1k) - Address range: 0xd400 - 0xd7ff - Bit pattern: 0b110101.......... */ -o5 = (!i0 # !i1 # i2 # !i3 # i4 # !i5); +o2 = ((!i3 & !i4) # (i3 & i4)) & i0 & i1 & !i2; +o4 = ((!i3 & i4) # (i3 & i4)) & i0 & i1 & !i2; +o5 = ((!i3 & i4) # (i3 & !i4)) & i0 & i1 & !i2; /* Inverter This is not part of the bus logic. @@ -71,19 +84,3 @@ o5 = (!i0 # !i1 # i2 # !i3 # i4 # !i5); */ o7 = !reset_in; - -/* -oe# we#, and ce# for the memory chips must be -qualified by phi - No memory access -in the first part of the cycle, while phi -is low. -*/ - -/* ram_oe# */ -o1 = !phi # !rwb; - -/* ram_ce# */ -o3 = !phi # i0; - -/* ram_we# */ -o6 = !phi # rwb; diff --git a/misc/write_default_files.sh b/misc/write_default_files.sh @@ -1,7 +1,17 @@ -#!/bin/sh +#!/bin/bash GFS_CMD="sudo ../tools/gfs.py" SW=../sw +for i in 10print ansi_test serial_line_echo stack_test ttt via_test +do + pushd ../sw/$i + make clean all + popd +done +pushd ../sw/ttt +make test +popd + ${GFS_CMD} format ${GFS_CMD} store 0 "10print" ${SW}/10print/10print.bin ${GFS_CMD} store 1 "Tic Tac Toe" ${SW}/ttt/ttt.bin diff --git a/roms/Makefile.common b/roms/Makefile.common @@ -1,12 +1,29 @@ -CFLAGS=-C --line-numbers --tab-size=1 -Wall -c -b --labels-root=export +CFLAGS=-C --line-numbers --tab-size=1 -Wall -c -b + +LABELS=--labels-root=export -l $(TARGET).l \ + --labels-root=io -l io.l \ + --labels-root=ds -l ds.l \ + --labels-root=sd -l sd.l \ + --labels-root=lfsr -l lfsr.l \ + --labels-root=spi -l spi.l \ + --labels-root=term -l term.l + +LABELS_SYMON=--labels-root=export -l $(TARGET)_symon.l \ + --labels-root=io -l io_symon.l \ + --labels-root=ds -l ds_symon.l \ + --labels-root=sd -l sd_symon.l \ + --labels-root=lfsr -l lfsr_symon.l \ + --labels-root=spi -l spi_symon.l \ + --labels-root=term -l term_symon.l + all: $(TARGET).bin $(TARGET)_symon.bin %.bin: %.asm - 64tass $(CFLAGS) -DSYMON=false -l $(TARGET).l -L $(TARGET).lst "$<" -o "$@" + 64tass $(CFLAGS) -DSYMON=false $(LABELS) -L $(TARGET).lst "$<" -o "$@" %_symon.bin: %.asm - 64tass $(CFLAGS) -DSYMON=true -l $(TARGET)_symon.l -L $(TARGET)_symon.lst "$<" -o "$@" + 64tass $(CFLAGS) -DSYMON=true $(LABELS_SYMON) -L $(TARGET)_symon.lst "$<" -o "$@" flash: $(TARGET).bin sudo ~/opt/minipro-0.3/minipro -p AT28C64B -w $< diff --git a/roms/boot/ansi.asm b/roms/boot/ansi.asm @@ -1,281 +0,0 @@ -;;; -;;; Special commands for ANSI terminals -;;; - -.namespace export -;;; ANSI text attributes -plain = 0 -bold = 1 -blink = 5 -reverse = 7 - -;;; ANSI colors -black = 0 -red = 1 -green = 2 -yellow = 3 -blue = 4 -magenta = 5 -cyan = 6 -white = 7 -bright_black = 8 -bright_red = 9 -bright_green = 10 -bright_yellow = 11 -bright_blue = 12 -bright_magenta = 13 -bright_cyan = 14 -bright_white = 15 -.endn - -;;; get_screen_size -;;; Returns screen size in X, A. -;;; If not supported by terminal, C is set -;;; Input: -;;; - -;;; Output: -;;; X: Screen width -;;; A: Screen height -;;; Changes: -;;; a, x, y, c -.namespace export -get_screen_size: -.endn - .block - jsr export.create_stack_frame - PUSH $02 - cursor_save_x = 0 ; Local variable - cursor_save_y = 1 ; Local variable - ;; Local variables 0 & 1: Saved cursor position - jsr export.get_cursor ; Save cursor position - bcs terminal_does_not_answer - sta_LOCAL cursor_save_y - txa - sta_LOCAL cursor_save_x - #SET_CURSOR #$FF, #$FF ; Try to move cursor to max. position - jsr export.get_cursor ; Get cursor position (= screen size) - pha ; Save it temporary - txa ; on the - pha ; hardware stack. - lda_LOCAL cursor_save_x ; Restore - tax ; old - lda_LOCAL cursor_save_y ; cursor - jsr export.set_cursor ; position - jsr export.delete_stack_frame - pla - tax - pla - rts -terminal_does_not_answer: - jsr export.delete_stack_frame - ldx #80 - lda #25 - rts - .bend - -.namespace export -clear_screen: -.endn - PRINTS x"1b" .. "[2J" - rts - -.namespace export -set_color: -.endn - pha - PRINTS x"1b" .. "[38;5;" - pla - jsr export.putd - lda #"m" - jmp export.putc - -.namespace export -set_background_color: -.endn - pha - PRINTS x"1b" .. "[48;5;" - pla - jsr export.putd - lda #"m" - jmp export.putc - -.namespace export -set_text: -.endn - tax - lda #"m" - jmp send_CSI - -.namespace export -cursor_up: -.endn - tax - lda #"A" - jmp send_CSI - -.namespace export -cursor_down: -.endn - tax - lda #"B" - jmp send_CSI - -.namespace export -cursor_forward: -.endn - tax - lda #"C" - jmp send_CSI - -.namespace export -cursor_back: -.endn - tax - lda #"D" - jmp send_CSI - -.namespace export -scroll_up: -.endn - tax - lda #"S" - jmp send_CSI - -.namespace export -scroll_down: -.endn - tax - lda #"T" - jmp send_CSI - -;;; Send ANSI escape sequence to terminal. -;;; A contains command, X value -send_CSI: - pha - phx - lda #$1b - jsr export.putc - lda #"[" - jsr export.putc - pla - jsr export.putd - pla - jmp export.putc - -;;; set_cursor -;;; Sets cursor to position x, a. -;;; Position starts at 1, not 0! -;;; Input: -;;; x: x position -;;; a: y position -;;; Output: -;;; - -;;; Changes: -;;; a, x, y, c -;;; Set Cursor; x position in X, y position in A -.namespace export -set_cursor: -.endn - phx - pha - lda #$1b - jsr export.putc - lda #"[" - jsr export.putc - pla - jsr export.putd - lda #";" - jsr export.putc - pla - jsr export.putd - lda #"H" - jmp export.putc - -;;; get_cursor -;;; Store cursor position in x, a. -;;; Position starts at 1, not 0! -;;; Input: -;;; - -;;; Output: -;;; x: x position -;;; a: y position -;;; Changes: -;;; a, x, y, c -.namespace export -get_cursor: -.endn - .block - jsr export.create_stack_frame - PUSH $08 ; Position as string - ;; We store the position string as local variables. - ;; By initializing the local variables with #$00, - ;; the strings terminate automatically when no - ;; more digits are written. - lda #$00 - .for i = 0, i < 8, i += 1 - sta_LOCAL i - .next - ;; Request cursor position - PRINTS x"1b" .. "[6n" - ;; Read answer - ldx #$08 ; Number of tries - ldy #$ff ; to get an answer. -wait_for_answer: - phx - phy - jsr export.getc_nonblocking ; $1b - ply - plx - bcc terminal_answers - dey - cpy #$00 - bne wait_for_answer - dex - cpx #$00 - bne wait_for_answer - ;; Terminal does not answer. - jsr export.delete_stack_frame - lda #$00 - ldx #$00 - sec - rts -terminal_answers: - jsr export.getc ; "[" - jsr export.getc ; First digit y - sta_LOCAL 0 - jsr export.getc ; Second digit y - cmp #";" - beq got_y_position - sta_LOCAL 1 - jsr export.getc ; Third digit y - cmp #";" - beq got_y_position - sta_LOCAL 2 -got_y_position: - jsr export.getc ; First digit x - sta_LOCAL 4 - jsr export.getc ; Second digit x - cmp #"R" - beq got_x_position - sta_LOCAL 5 - jsr export.getc ; Third digit x - cmp #"R" - beq got_x_position - sta_LOCAL 6 -got_x_position: - ;; x position is in local variable(s) 4... - ;; y position is in local variable(s) 0... - ;; Convert them to ints - CALL export.str2byte, [0, 1, 2, 3], lda_LOCAL - lda_PARAM 0 - pha - CALL export.str2byte, [4, 5, 6, 7], lda_LOCAL - lda_PARAM 0 - pha - jsr export.delete_stack_frame - plx - pla - clc - rts - .bend - diff --git a/roms/boot/ansi.inc b/roms/boot/ansi.inc @@ -1,59 +0,0 @@ -;;; -*- asm -*- - -;;; ----------------------------------- -;;; -;;; ANSI Terminal -;;; -;;; ----------------------------------- - -SET_COLOR .macro color - lda #color - jsr set_color - .endm - -SET_BACKGROUND_COLOR .macro color - lda #color - jsr set_background_color - .endm - -SET_TEXT .macro attribute - lda #\attribute - jsr set_text - .endm - -CURSOR_UP .macro steps - lda #\steps - jsr cursor_up - .endm - -CURSOR_DOWN .macro steps - lda #\steps - jsr cursor_down - .endm - -CURSOR_FORWARD .macro steps - lda #\steps - jsr cursor_forward - .endm - -CURSOR_BACK .macro steps - lda #\steps - jsr cursor_back - .endm - -SCROLL_UP .macro steps - lda #\steps - jsr scroll_up - .endm - -SCROLL_DOWN .macro steps - lda #\steps - jsr scroll_DOWN - .endm - -SET_CURSOR .macro x, y - lda \y - ldx \x - jsr export.set_cursor - .endm - diff --git a/roms/boot/boot.asm b/roms/boot/boot.asm @@ -1,4 +1,3 @@ - DEBUG = false ;; DEBUG = true @@ -19,31 +18,7 @@ .dsection rom .cerror * > $ffff, "ROM exhausted" -export .namespace -.section zero_page - ;; LFSR -lfsr_state: .word ? - ;; Stack -ds_pointer: .word ? -ds_frame: .word ? - ;; Temporary zero page variables; - ;; only used in subroutine -puts_str: .word ? -gets_len: .byte ? -gets_str: .word ? - ;; Used by VIA for (de-)serialization -via_buffer: .byte ? -sd_data: .word ? - ;; sd_type does not need to be on the zero page. - ;; We may want to move it to $200-$2ff. -sd_type: .byte ? ; $05 = SD; $c1 = SDHC - ;; Everything beyond these reserved variables available to - ;; programs in RAM. -rom_zero_page_end: -.send zero_page -.endn - -.namespace export +export .namespace ram_end = $7fff .endn @@ -67,13 +42,13 @@ irq_vector = export.ram_end - $1 boot: .block sei - #STORE_WORD export.default_irq_handler, export.irq_vector - #STORE_WORD export.default_nmi_handler, export.nmi_vector + #mem.STORE_WORD export.default_irq_handler, export.irq_vector + #mem.STORE_WORD export.default_nmi_handler, export.nmi_vector cld cli - jsr export.init_acia - INIT_STACK export.ram_end-$206+$1 ;Minimal stack size to access SD card - jsr export.init_via + jsr io.init_acia + #ds.INIT_STACK export.ram_end-$206+$1 ;Minimal stack size to access SD card + jsr spi.init_via jsr check_for_program_download bcs no_program_download jmp download_program @@ -88,18 +63,18 @@ no_program_download: ;;; The value of the byte is the number of $100 byte ;;; blocks to receive. check_for_program_download: .block - #PRINTSNL "READY!" + #io.PRINTSNL "READY!" ldy #$20 ; Outer loop counter ldx #$00 ; Inner counter loop: ;; Try to get number of 0x100 byte blocks to be read - jsr export.getc_nonblocking + jsr io.getc_nonblocking bcc got_byte dex bne loop dey bne loop - #PRINTSNL "Nothing to download." + #io.PRINTSNL "Nothing to download." sec got_byte: rts @@ -133,7 +108,7 @@ download_program: .block sta add_checksum sta xor_checksum transmit_block: - jsr export.getc + jsr io.getc ;; Store data ldy #$00 sta (addr_pointer), y @@ -159,21 +134,27 @@ transmit_block: ;; Transmission completed. ;; Transmit result of checksum calculation lda add_checksum - jsr export.putc + jsr io.putc lda xor_checksum - jsr export.putc + jsr io.putc ;; Start program jmp $0200 .bend .include "io.asm" -.include "stack.asm" +.include "ds.asm" .include "lfsr.asm" .include "spi.asm" -.include "sd_card.asm" -.include "ansi.asm" +.include "sd.asm" +.include "term.asm" +.namespace export +.section zero_page +rom_zero_page_end: +.send zero_page +.endn + ;;; Default IRQ handler. Unless the user program changes ;;; the irq_vector, IRQs are handled here. .namespace export diff --git a/roms/boot/boot.inc b/roms/boot/boot.inc @@ -12,33 +12,48 @@ CLOCK_SPEED = 0 .endweak .if CLOCK_SPEED == 0 + .if SYMON + filename_addition = "_symon" + start_address = $0300 + .else + filename_addition = "" + start_address = $0200 + .endif export .namespace - puts = puts - puth = puth - puts_str = puts_str - gets_str = gets_str - gets_len = gets_len - gets = gets - putc = putc - putd = putd - create_stack_frame = create_stack_frame - delete_stack_frame = delete_stack_frame - push_a = push_a - pull_a = pull_a - ds_pointer = ds_pointer - ds_frame = ds_frame - ram_end = ram_end - set_cursor = set_cursor + .include "boot" .. filename_addition .. ".l" + .endn + io .namespace + .include "io" .. filename_addition .. ".l" + .endn + ds .namespace + .include "ds" .. filename_addition .. ".l" + .endn + sd .namespace + .include "sd" .. filename_addition .. ".l" + .endn + lfsr .namespace + .include "lfsr" .. filename_addition .. ".l" + .endn + spi .namespace + .include "spi" .. filename_addition .. ".l" + .endn + term .namespace + .include "term" .. filename_addition .. ".l" .endn BOOT_EMBEDDED = false + ;; Set start addresses for program and + ;; zero page variables + * = export.rom_zero_page_end + .dsection zero_page + * = start_address .else BOOT_EMBEDDED = true .endif - + .include "io.inc" -.include "stack.inc" -.include "sd_card.inc" -.include "ansi.inc" +.include "ds.inc" +.include "sd.inc" +.include "term.inc" ;;; ----------------------------------- ;;; @@ -46,6 +61,8 @@ ;;; ;;; ----------------------------------- +mem .namespace + SET_BITS .macro lda \1 ora \2 @@ -115,3 +132,5 @@ ADD_WORD: .macro adc #>\2 sta \1+1 .endm + +.endn diff --git a/roms/boot/ds.asm b/roms/boot/ds.asm @@ -0,0 +1,76 @@ +;;; ---------------------------------------------------------- +;;; +;;; STACK +;;; +;;; ---------------------------------------------------------- + +;;; Software implementation of data stack. In difference to typical +;;; stack implementations, this stack grows from bottom to top, because +;;; we want to access eleements using indirected indexed access with +;;; the stack frame pointer as base. Therefore the stack should +;;; be initialized with the first unoccupied RAM address after the +;;; program code. +;;; +;;; PULL and PUSH do not move actual stack data, they just shift +;;; the stack pointer. +;;; +;;; Local variables on the data stack are supported by macro +;;; VAR. VAR i refers to the ith byte on the stack. PARAM allows +;;; to pass variables to a callee. PARAM i of the caller becomes +;;; VAR i of the callee. The callee should reserve stack space +;;; for both its parameters and local variables. +;;; +;;; Stack frames used for these calls are created/destroyed by +;;; subroutines create_stack_frame and delete_stack_frame. +;;; +;;; CALL is like jsr with parameter passing. There addressing +;;; modes are supported: immediate, zero-page, and local variables. +;;; For immediate and zero page, the third parameter must be lda. +;;; For local variables, the third parameter must be lda_LOCAL. +;;; See sw/stack_test/stack_test.asm for examles. + +ds .namespace + +.section zero_page + ;; Stack +ptr: .word ? +frame_ptr: .word ? +.send zero_page + +.section rom + +create_stack_frame: + .block + ;; Store old frame pointer on stack. + ;; Since our stack grows bottom to top, we write + ;; the data before increasing the stack pointer + #mem.COPY_WORD_ABSOLUTE_INDIRECT ds.frame_ptr, (ds.ptr) + #ds.PUSH $02 ; Store old frame pointer + #mem.COPY_WORD_ABSOLUTE_INDIRECT ds.ptr, ds.frame_ptr ; Set new frame pointer + rts + .bend + +delete_stack_frame: + .block + #mem.COPY_WORD_ABSOLUTE_INDIRECT ds.frame_ptr, ds.ptr ; Reset stack pointer to begin of frame. + #ds.PULL $02 ; Move stack pointer to frame reference + #mem.COPY_WORD_ABSOLUTE_INDIRECT (ds.ptr), ds.frame_ptr ; Restore old frame pointer. + rts + .bend + +push_a: + .block + sta (ds.ptr) + #ds.PUSH $01 + rts + .bend + +pull_a: + .block + #ds.PULL $01 + lda (ds.ptr) + rts + .bend + +.send rom +.endn diff --git a/roms/boot/ds.inc b/roms/boot/ds.inc @@ -0,0 +1,79 @@ +;;; -*- asm -*- + +;;; Macros for accessing the data stack +;;; and managing local variables and +;;; call parameters. Check ds.asm for +;;; documentation. + +.namespace ds + +INIT_STACK: .macro + #mem.STORE_WORD \1, ds.ptr + .endm + +PUSH: .macro ; Reserve bytes on stack (no actual push operation) + #mem.ADD_WORD ds.ptr, \1 + .endm + +PULL: .macro ; Remove bytes from stack (no return value) + #mem.SUB_WORD ds.ptr, \1 + .endm + +PUSH_WORD: .macro ; Push a word on the stack + lda #<\1 + sta (ds.ptr) + lda #>\1 + ldy #$01 + sta (ds.ptr),y + #ds.PUSH $02 + .endm + +LOCAL: .macro + ldy #\1 + \2 (ds.frame_ptr),y + .endm +lda_LOCAL: .macro + #ds.LOCAL \1, lda + .endm +sta_LOCAL: .macro + #ds.LOCAL \1, sta + .endm +adc_LOCAL: .macro + #ds.LOCAL \1, adc + .endm +PARAM: .macro + ldy #\1 + \2 (ds.ptr),y + .endm +sta_PARAM: .macro + #ds.PARAM \1+2, sta + .endm +lda_PARAM: .macro + #ds.PARAM \1+2, lda + .endm + +CALL: .macro subroutine, param=[], param_lda="" + .block + .if len(\param) != 0 + .for CALL_param := 0, CALL_param < len(\param), CALL_param += $1 + \param_lda \param[CALL_param] + #ds.sta_PARAM CALL_param + .next + .endif + jsr \subroutine + .bend + .endm + +;; Push sequence of bytes to stack. Parameters: From, Length +PUSH_RANGE: .macro + ldy #$00 +loop_PUSH_RANGE: + lda \1,y + sta (ds_pointer),y + iny + cpy \2 + bne loop_PUSH_RANGE + #PUSH \2 + .endm + +.endn diff --git a/roms/boot/io.asm b/roms/boot/io.asm @@ -1,45 +1,18 @@ ;;; Serial IO and string manipulation - -.namespace export + +io .namespace + .if SYMON - acia_base = $8800 ; Symon + acia_base = $8800 + via_start = $8000 .else - acia_base = $dc00 + acia_base = $c000 + via_start = $c800 .endif acia_data_reg = acia_base acia_status_reg = acia_base + $1 acia_cmd_reg = acia_base + $2 acia_ctrl_reg = acia_base + $3 -.endn - -;;; init_acia -;;; Initialize acai for communication -;;; Input: -;;; - -;;; Output: -;;; - -;;; Changes: -;;; a, acai registers -.namespace export -init_acia: -.endn - .block - ;; Reset acai - sta export.acia_status_reg - lda #%00011111 ; 19200 bps, 8 data bits, 1 stop bit - sta export.acia_ctrl_reg - ;; No parity, no echo, no interrupts, DTR ready - lda #%11001011 - sta export.acia_cmd_reg - rts - .bend - -.namespace export -.if SYMON - via_start = $8000 -.else - via_start = $d800 -.endif via_irb = via_start via_orb = via_start via_ira = via_start+$1 @@ -59,7 +32,37 @@ init_acia: via_ier = via_start+$14 via_ira2 = via_start+$15 via_ora2 = via_start+$15 -.endn + + +.section zero_page + ;; Temporary zero page variables; + ;; only used in subroutine +puts_str: .word ? +gets_len: .byte ? +gets_str: .word ? +.send zero_page + +.section rom + +;;; init_acia +;;; Initialize acai for communication +;;; Input: +;;; - +;;; Output: +;;; - +;;; Changes: +;;; a, acai registers +init_acia: + .block + ;; Reset acai + sta io.acia_status_reg + lda #%00011111 ; 19200 bps, 8 data bits, 1 stop bit + sta io.acia_ctrl_reg + ;; No parity, no echo, no interrupts, DTR ready + lda #%11001011 + sta io.acia_cmd_reg + rts + .bend ;;; ---------------------------------------------------------- ;;; STANDARD LIBRARY FUNCTIONS @@ -79,17 +82,15 @@ init_acia: ;;; - ;;; Changes: ;;; a, x, y, puts_str, put_str+1 -.namespace export puts: -.endn .block ;; Send string terminated by '\0' ldy #$00 _puts_loop: - lda (export.puts_str),y + lda (io.puts_str),y beq _puts_end phy - jsr export.putc + jsr io.putc ply iny jmp _puts_loop @@ -106,15 +107,13 @@ _puts_end: ;;; - ;;; Changes: ;;; x, acai registers -.namespace export putc: -.endn .block ;; Send character. ;; Due to bugs in the register and interrupt ;; handling of the WDC 65C02, we have to use ;; a manual delay. - sta export.acia_data_reg + sta io.acia_data_reg .switch CLOCK_SPEED .case 4 ; 4 Mhz Clock SERIAL_SEND_DELAY_X = $c3 @@ -146,9 +145,7 @@ inner_loop: ;;; - ;;; Changes: ;;; a, x, acai registers, c-flag -.namespace export puth: -.endn .block ;; Send byte a as hex number pha @@ -156,9 +153,9 @@ puth: lsr a lsr a lsr a - jsr export.puth_nibble + jsr io.puth_nibble pla - jsr export.puth_nibble + jsr io.puth_nibble rts .bend @@ -171,9 +168,7 @@ puth: ;;; - ;;; Changes: ;;; a, x, acai registers, c-flag -.namespace export puth_nibble: -.endn .block ;; Print hex digit clc @@ -183,7 +178,7 @@ puth_nibble: bmi _puth_putc adc #$26 _puth_putc: - jsr export.putc + jsr io.putc rts .bend @@ -196,9 +191,7 @@ _puth_putc: ;;; - ;;; Changes: ;;; a, x, y, acai registers, c-flag -.namespace export putd: -.endn .block ldy #$00 first_digit: @@ -213,7 +206,7 @@ first_digit_set: pha tya beq skip_first_leading_zero - jsr export.puth_nibble + jsr io.puth_nibble ldx #$01 ; Force printing of zeros in rest of term skip_first_leading_zero: pla @@ -232,10 +225,10 @@ second_digit_set: cmp #$00 beq skip_second_leading_zero do_not_skip_potential_second_leading_zero: - jsr export.puth_nibble + jsr io.puth_nibble skip_second_leading_zero: pla - jmp export.puth_nibble + jmp io.puth_nibble .bend @@ -247,14 +240,12 @@ skip_second_leading_zero: ;;; - ;;; Changes: ;;; a -.namespace export putnl: -.endn .block lda #$0d - jsr export.putc + jsr io.putc lda #$0a - jsr export.putc + jsr io.putc rts .bend @@ -267,15 +258,13 @@ putnl: ;;; Character read ;;; Changes: ;;; a, acai registers -.namespace export getc: -.endn .block ;; Read character from acia - lda export.acia_status_reg + lda io.acia_status_reg and #%00001000 - beq export.getc - lda export.acia_data_reg + beq io.getc + lda io.acia_data_reg rts .bend @@ -291,24 +280,20 @@ getc: ;;; Character read ;;; Changes: ;;; a, acai registers, lsfr_state -.namespace export getc_seed_rng: -.endn .block ;; Read character from acia ;; We also use the time between keystrokes ;; as entropy source for the RNG - jsr export.lfsr_step - lda export.acia_status_reg + jsr lfsr.step + lda io.acia_status_reg and #%00001000 - beq export.getc_seed_rng - lda export.acia_data_reg + beq io.getc_seed_rng + lda io.acia_data_reg rts .bend -.namespace export getc_nonblocking: -.endn .block ;; Non-blocking read: If ;; character has been read, @@ -316,11 +301,11 @@ getc_nonblocking: ;; C is cleared. If not, ;; C is set sec - lda export.acia_status_reg + lda io.acia_status_reg and #%00001000 beq nothing_read clc - lda export.acia_data_reg + lda io.acia_data_reg nothing_read: rts .bend @@ -341,26 +326,24 @@ nothing_read: ;;; Zero terminated string at gets_str, gets_str+1 ;;; Changes: ;;; a, y, ACAI registers -.namespace export gets: -.endn .block ;; Read string terminated by CR ldy #$00 loop: phy - jsr export.getc - jsr export.putc + jsr io.getc + jsr io.putc ply cmp #$0d ; GOT CR? beq terminate_string ; if not - sta (export.gets_str), y ; store character + sta (io.gets_str), y ; store character iny ; if max length - cpy export.gets_len ; not reached, + cpy io.gets_len ; not reached, bne loop ; continue loop. terminate_string: lda #$00 - sta (export.gets_str), y + sta (io.gets_str), y rts .bend @@ -374,32 +357,30 @@ terminate_string: ;;; Byte value ;;; Changes: ;;; a, x, y -.namespace export str2byte: -.endn .block - jsr export.create_stack_frame - PUSH $04 ; Local variable (string of length four) + jsr ds.create_stack_frame + #ds.PUSH $04 ; Local variable (string of length four) lda #$00 pha ldy #$00 add_digit: - lda (export.ds_frame),y + lda (ds.frame_ptr),y beq done sec ; Convert next digit sbc #'0' ; from ascii to - sta (export.ds_frame),y ; number. + sta (ds.frame_ptr),y ; number. pla ; Multiply current - jsr export.multiply_by_ten ; accumulator by 10. + jsr io.multiply_by_ten ; accumulator by 10. clc ; Add new - adc (export.ds_frame),y ; digit. + adc (ds.frame_ptr),y ; digit. pha iny ; Advance to next digit jmp add_digit done: pla - sta_LOCAL 0 - jsr export.delete_stack_frame + #ds.sta_LOCAL 0 + jsr ds.delete_stack_frame .bend ;;; multiply_by_ten @@ -410,15 +391,16 @@ done: ;;; a: Number * 10 ;;; Changes: ;;; a, c -.namespace export multiply_by_ten: -.endn .block - sta (export.ds_pointer) + sta (ds.ptr) lda #$00 clc .for i = 0, i < 10, i += 1 - adc (export.ds_pointer) + adc (ds.ptr) .next rts .bend + +.send rom +.endn diff --git a/roms/boot/io.inc b/roms/boot/io.inc @@ -1,5 +1,7 @@ ;;; -*- asm -*- +.namespace io + ;;; PRINT(addr) ;;; Send zero terminated string at addr via acia. ;;; Input: @@ -12,10 +14,10 @@ PRINT .macro lda #<\1 - sta export.puts_str + sta io.puts_str lda #>\1 - sta export.puts_str+1 - jsr export.puts + sta io.puts_str+1 + jsr io.puts .endm ;;; PRINTS(string) (<= 255 characters) @@ -29,7 +31,7 @@ PRINT .macro ;;; a, x, y, puts_str, put_str+1 PRINTS .macro - PRINT(saddr) + #io.PRINT saddr jmp cont_PRINTS saddr: .null \1 @@ -47,7 +49,7 @@ cont_PRINTS: ;;; a, x, y, puts_str, put_str+1 PRINTSNL .macro - PRINT(saddr) + #io.PRINT saddr jmp cont_PRINTSNL saddr: .null \1, $0d, $0a @@ -74,12 +76,12 @@ cont_PRINTSNL: INPUTS .macro lda #<\1 - sta export.gets_str + sta io.gets_str lda #>\1 - sta export.gets_str+1 + sta io.gets_str+1 lda \2 - sta export.gets_len - jsr export.gets + sta io.gets_len + jsr io.gets .endm ;;; PRINTNL @@ -93,8 +95,9 @@ INPUTS .macro PRINTNL .macro lda #$0d - jsr export.putc + jsr io.putc lda #$0a - jsr export.putc + jsr io.putc .endm +.endn diff --git a/roms/boot/lfsr.asm b/roms/boot/lfsr.asm @@ -4,7 +4,7 @@ ;;; bit from the state yields random numbers with reasonable ;;; statistical properties. -;;; lfsr_init +;;; init ;;; Initialize lfsr ;;; Input: ;;; - @@ -12,14 +12,21 @@ ;;; - ;;; Changes: ;;; lfsr -.namespace export -lfsr_init: -.endn +lfsr .namespace + +.section zero_page + ;; LFSR +state: .word ? +.send zero_page + +.section rom + +init: .block - #STORE_WORD $beef, export.lfsr_state + #mem.STORE_WORD $beef, lfsr.state .bend -;;; lfsr_step +;;; step ;;; update lfsr ;;; Input: ;;; - @@ -27,20 +34,18 @@ lfsr_init: ;;; - ;;; Changes: ;;; lfsr -.namespace export -lfsr_step: -.endn +step: .block - asl export.lfsr_state - lda export.lfsr_state+1 + asl lfsr.state + lda lfsr.state+1 rol a bcc cont eor #$0b cont: - sta export.lfsr_state+1 - lda export.lfsr_state + sta lfsr.state+1 + lda lfsr.state adc #$00 - sta export.lfsr_state + sta lfsr.state rts .bend @@ -48,14 +53,16 @@ cont: ;;; Test function for LFSR test_lfsr: .block loop: - jsr export.lfsr_step - lda export.lfsr_state+1 + jsr lfsr.step + lda lfsr.state+1 jsr puth - lda export.lfsr_state - jsr export.puth + lda lfsr.state + jsr io.puth PRINTSNL("") - jsr export.getc + jsr io.getc jmp loop .bend .endif ; false +.send rom +.endn diff --git a/roms/boot/sd.asm b/roms/boot/sd.asm @@ -0,0 +1,269 @@ +;; ----------------------------------- +;;; +;;; SD card communication interface +;;; +;;; ----------------------------------- + + +sd .namespace + +.section zero_page +data: .word ? + ;; type does not need to be on the zero page. +type: .byte ? ; $05 = SD; $c1 = SDHC + ;; Everything beyond these reserved variables available to + ;; programs in RAM. +.send zero_page + +.section rom + +send_cmd: + .block + ldy #$00 +cmd_bytes_loop: + lda (sd.data),y + jsr spi.set + iny + cpy #$06 + bne cmd_bytes_loop + lda #$ff ; Finalize transmission + jsr spi.set ; with dummy byte + rts + .bend + + +print_block: + .block + ldx #$02 + ldy #$00 +loop: + phx + phy + lda (sd.data),y + jsr io.puth + #io.PRINTS " " + ply + plx + iny + bne loop + #mem.ADD_WORD sd.data, $0100 + dex + bne loop + #io.PRINTNL + #mem.SUB_WORD sd.data, $0200 + rts + .bend + +read_block: + ;; Read a block of data + ;; Block number is passed via stack. + .block + jsr ds.create_stack_frame + #ds.PUSH $04 ; Local variable (32 bit block number) +.if DEBUG + io.PRINTSNL "Sending CMD17" +.endif + lda #$51 ; CMD17 (READ_SINGLE_BLOCK) + jsr spi.set + jsr send_block_number + lda #$01 ; Dummy CRC + jsr spi.set + jsr spi.get + cmp #$00 + beq wait_for_start_token + jmp read_failed +wait_for_start_token: + jsr spi.get_nonblocking + cmp #$ff + beq wait_for_start_token + cmp #$fe + bne read_failed + ldx #$02 + ldy #$00 +loop: + phx + phy + jsr spi.get_nonblocking + ply + plx + sta (sd.data),y + iny + bne loop + #mem.ADD_WORD sd.data, $0100 ; Second half of block + dex + bne loop + #mem.SUB_WORD sd.data, $0200 ; Restore pointer + clc + #sd.RECEIVE $2 ; Get CRC + jsr ds.delete_stack_frame + rts +read_failed: + #io.PRINTSNL "Error reading SD card!" + sec + jsr ds.delete_stack_frame + rts + .bend + +send_block_number: + .block + lda sd.type ; Old cards expect the position + cmp #$05 ; as bytes, not blocks + beq old_card + #ds.lda_LOCAL 0 ; Block number + jsr spi.set + #ds.lda_LOCAL 1 + jsr spi.set + #ds.lda_LOCAL 2 + jsr spi.set + #ds.lda_LOCAL 3 + jsr spi.set + rts +old_card: + #ds.lda_LOCAL 3 + asl a + #ds.sta_LOCAL 3 + #ds.lda_LOCAL 2 + rol a + #ds.sta_LOCAL 2 + #ds.lda_LOCAL 1 + rol a + jsr spi.set + #ds.lda_LOCAL 2 + jsr spi.set + #ds.lda_LOCAL 3 + jsr spi.set + lda #$00 + jsr spi.set + rts + .bend + +write_block: + ;; Write block at data to card. + ;; Block number is passed via stack. + .block + jsr ds.create_stack_frame + #ds.PUSH $04 ; Local variable (32 bit block number) +.if DEBUG + io.PRINTSNL "Sending CMD24" +.endif + lda #$58 ; CMD24 (WRITE_BLOCK) + jsr spi.set + jsr send_block_number + lda #$01 ; Dummy CRC + jsr spi.set + lda #$ff + jsr spi.set ; Dummy byte + #sd.RECEIVE $1 + ;; Send start token + lda #$fe + jsr spi.set + ;; Send data + ldx #$02 + ldy #$00 +write_loop: + phx + phy + lda (sd.data),y + jsr spi.set + ply + plx + iny + cpy #$00 + bne write_loop + #mem.ADD_WORD sd.data, $0100 ; Second half of block + dex + cpx #$00 + bne write_loop + #mem.SUB_WORD sd.data, $0200 ; Restore pointer + ;; Wait for write operation to complete + #sd.RECEIVE $1 + cmp #$e5 + bne error_writing +wait_loop: + #sd.RECEIVE $1 + beq wait_loop + jsr ds.delete_stack_frame + clc + rts +error_writing: + #io.PRINTSNL "Error writing to SD card!" + jsr ds.delete_stack_frame + sec + rts + .bend + +close: + #mem.SET_BITS io.via_ora, #spi.CS + rts + +open: + .block +.if DEBUG + #io.PRINTSNL "Initializing SD Card" +.endif + ;; Configure ports for in- and output + #mem.SET_BITS io.via_ddra, #(spi.CS | spi.SCK | spi.MOSI) + #mem.CLEAR_BITS io.via_ddra, #spi.MISO + ldy #$10 ; Error counter + phy +start_init: + ;; Card power on sequence: + ;; Keep CS high, toggle clock for at least 74 cycles. + #mem.SET_BITS io.via_ora, #(spi.CS | spi.MOSI) + ;; Wait for 80 clock pulses + ldx #160 +boot_wait_loop: + #mem.TOGGLE_BITS io.via_ora, #spi.SCK + dex + bne boot_wait_loop + #mem.CLEAR_BITS io.via_ora, #(spi.CS|spi.MOSI|spi.SCK) + #sd.SEND_CMD [$40, $00, $00, $00, $00, $95] ; CMD0 + #sd.RECEIVE $1 + cmp #$01 ; Should be $01 (In idle state). + beq cont + ply + dey + phy + beq failed_init + jmp start_init ; If not, start over. +failed_init: + ply + #io.PRINTSNL "Error initializing SD card!" + sec + rts +cont: + ;; Card is in SPI mode + ply + #sd.SEND_CMD [$48, $00, $00, $01, $aa, $87] ; CMD8 + #sd.RECEIVE $1 + #sd.SEND_CMD [$45, $00, $00, $00, $00, $5b] ; CMD5 + #sd.RECEIVE $1 ; $05 = SD; $c1 = SDHC + sta sd.type + #sd.SEND_CMD [$7b, $00, $00, $00, $00, $83] ; CMD59 + #sd.RECEIVE $1 ; should be $01 + ;; Send ACMD41 until card is initialized + ldy #$10 ; Fail counter + phy +wait_for_card_initialized: + #sd.SEND_CMD [$77, $00, $00, $00, $00, $65] ; CMD55 + #sd.RECEIVE $1 ; should be $01 + #sd.SEND_CMD [$69, $40, $00, $00, $00, $95] ; ACMD41 (v1 & v2 card) + #sd.RECEIVE $1 ; $01 if busy, $00 if ready (initialized) + cmp #$00 + beq initialized + ply + dey + phy + bne cont2 ; More tries? +cont2: + jmp wait_for_card_initialized +initialized: + ply + #sd.SEND_CMD [$50, $00, $00, $02, $00, $15] ; CMD16 + #sd.RECEIVE $1 + clc + rts + .bend + +.send rom +.endn diff --git a/roms/boot/sd.inc b/roms/boot/sd.inc @@ -0,0 +1,51 @@ +;;; -*- asm -*- + +;;; Macros for accessing SD cards + +.namespace sd + +SEND_CMD .macro +.if DEBUG + PRINTS "Sending CMD$" + lda cmd + sec + sbc #$40 + jsr io.puth + PRINTNL +.endif + lda #<cmd + sta sd.data + lda #>cmd + sta sd.data+1 + jsr sd.send_cmd + jmp cont_SEND_CMD +cmd: .byte \1 +cont_SEND_CMD: + .endm + + + +RECEIVE .macro + ldx #\1 +loop_RECEIVE: + phx + jsr spi.get +.if DEBUG + pha + jsr io.puth + PRINTS " " + pla +.endif + plx + dex + bne loop_RECEIVE + pha +.if DEBUG + PRINTNL +.endif + ;; Read non-existing dummy byte for snychronization + jsr spi.get_nonblocking + pla + .endm + +.endn diff --git a/roms/boot/sd_card.asm b/roms/boot/sd_card.asm @@ -1,266 +0,0 @@ -;;; ----------------------------------- -;;; -;;; SD card communication interface -;;; -;;; ----------------------------------- - - -;;; Send command -.namespace export -sd_send_cmd: -.endn - .block - ldy #$00 -cmd_bytes_loop: - lda (export.sd_data),y - jsr export.spi_set - iny - cpy #$06 - bne cmd_bytes_loop - lda #$ff ; Finalize transmission - jsr export.spi_set ; with dummy byte - rts - .bend - - -.namespace export -print_block: -.endn - .block - ldx #$02 - ldy #$00 -loop: - phx - phy - lda (export.sd_data),y - jsr export.puth - PRINTS " " - ply - plx - iny - bne loop - ADD_WORD export.sd_data, $0100 - dex - bne loop - PRINTNL - SUB_WORD export.sd_data, $0200 - rts - .bend - -.namespace export -sd_read_block: -.endn - ;; Read a block of data - ;; Block number is passed via stack. - .block - jsr export.create_stack_frame - PUSH $04 ; Local variable (32 bit block number) -.if DEBUG - PRINTSNL "Sending CMD17" -.endif - lda #$51 ; CMD17 (READ_SINGLE_BLOCK) - jsr export.spi_set - jsr sd_send_block_number - lda #$01 ; Dummy CRC - jsr export.spi_set - jsr export.spi_get - cmp #$00 - beq wait_for_start_token - jmp read_failed -wait_for_start_token: - jsr export.spi_get_nonblocking - cmp #$ff - beq wait_for_start_token - cmp #$fe - bne read_failed - ldx #$02 - ldy #$00 -loop: - phx - phy - jsr export.spi_get_nonblocking - ply - plx - sta (export.sd_data),y - iny - bne loop - ADD_WORD export.sd_data, $0100 ; Second half of block - dex - bne loop - SUB_WORD export.sd_data, $0200 ; Restore pointer - clc - SD_RECEIVE $2 ; Get CRC - jsr export.delete_stack_frame - rts -read_failed: - PRINTSNL("Error reading SD card!") - sec - jsr export.delete_stack_frame - rts - .bend - -sd_send_block_number: - .block - lda export.sd_type ; Old cards expect the position - cmp #$05 ; as bytes, not blocks - beq old_card - lda_LOCAL 0 ; Block number - jsr export.spi_set - lda_LOCAL 1 - jsr export.spi_set - lda_LOCAL 2 - jsr export.spi_set - lda_LOCAL 3 - jsr export.spi_set - rts -old_card: - lda_LOCAL 3 - asl a - sta_LOCAL 3 - lda_LOCAL 2 - rol a - sta_LOCAL 2 - lda_LOCAL 1 - rol a - jsr export.spi_set - lda_LOCAL 2 - jsr export.spi_set - lda_LOCAL 3 - jsr export.spi_set - lda #$00 - jsr export.spi_set - rts - .bend - -.namespace export -sd_write_block: -.endn - ;; Write block at sd_data to card. - ;; Block number is passed via stack. - .block - jsr export.create_stack_frame - PUSH $04 ; Local variable (32 bit block number) -.if DEBUG - PRINTSNL "Sending CMD24" -.endif - lda #$58 ; CMD24 (WRITE_BLOCK) - jsr export.spi_set - jsr sd_send_block_number - lda #$01 ; Dummy CRC - jsr export.spi_set - lda #$ff - jsr export.spi_set ; Dummy byte - SD_RECEIVE $1 - ;; Send start token - lda #$fe - jsr export.spi_set - ;; Send data - ldx #$02 - ldy #$00 -write_loop: - phx - phy - lda (export.sd_data),y - jsr export.spi_set - ply - plx - iny - cpy #$00 - bne write_loop - ADD_WORD export.sd_data, $0100 ; Second half of block - dex - cpx #$00 - bne write_loop - SUB_WORD export.sd_data, $0200 ; Restore pointer - ;; Wait for write operation to complete - SD_RECEIVE $1 - cmp #$e5 - bne error_writing -wait_loop: - SD_RECEIVE $1 - beq wait_loop - jsr export.delete_stack_frame - clc - rts -error_writing: - PRINTSNL("Error writing to SD card!") - jsr export.delete_stack_frame - sec - rts - .bend - -sd_close: - #SET_BITS export.via_ora, #CS - rts - -.namespace export -sd_open: -.endn - .block -.if DEBUG - PRINTSNL "Initializing SD Card" -.endif - ;; Configure ports for in- and output - SET_BITS export.via_ddra, #(CS | SCK | MOSI) - CLEAR_BITS export.via_ddra, #MISO - ldy #$10 ; Error counter - phy -start_init: - ;; Card power on sequence: - ;; Keep CS high, toggle clock for at least 74 cycles. - SET_BITS export.via_ora, #(CS | MOSI) - ;; Wait for 80 clock pulses - ldx #160 -boot_wait_loop: - TOGGLE_BITS export.via_ora, #SCK - dex - bne boot_wait_loop - CLEAR_BITS export.via_ora, #(CS|MOSI|SCK) - SD_SEND_CMD [$40, $00, $00, $00, $00, $95] ; CMD0 - SD_RECEIVE $1 - cmp #$01 ; Should be $01 (In idle state). - beq cont - ply - dey - phy - beq failed_init - jmp start_init ; If not, start over. -failed_init: - ply - PRINTSNL("Error initializing SD card!") - sec - rts -cont: - ;; Card is in SPI mode - ply - SD_SEND_CMD [$48, $00, $00, $01, $aa, $87] ; CMD8 - SD_RECEIVE $1 - SD_SEND_CMD [$45, $00, $00, $00, $00, $5b] ; CMD5 - SD_RECEIVE $1 ; $05 = SD; $c1 = SDHC - sta export.sd_type - SD_SEND_CMD [$7b, $00, $00, $00, $00, $83] ; CMD59 - SD_RECEIVE $1 ; should be $01 - ;; Send ACMD41 until card is initialized - ldy #$10 ; Fail counter - phy -wait_for_card_initialized: - SD_SEND_CMD [$77, $00, $00, $00, $00, $65] ; CMD55 - SD_RECEIVE $1 ; should be $01 - SD_SEND_CMD [$69, $40, $00, $00, $00, $95] ; ACMD41 (v1 & v2 card) - SD_RECEIVE $1 ; $01 if busy, $00 if ready (initialized) - cmp #$00 - beq initialized - ply - dey - phy - bne cont2 ; More tries? -cont2: - jmp wait_for_card_initialized -initialized: - ply - SD_SEND_CMD [$50, $00, $00, $02, $00, $15] ; CMD16 - SD_RECEIVE $1 - clc - rts - .bend - diff --git a/roms/boot/sd_card.inc b/roms/boot/sd_card.inc @@ -1,48 +0,0 @@ -;;; -*- asm -*- - -;;; Macros for accessing SD cards - -SD_SEND_CMD .macro -.if DEBUG - PRINTS "Sending CMD$" - lda cmd - sec - sbc #$40 - jsr export.puth - PRINTNL -.endif - lda #<cmd - sta export.sd_data - lda #>cmd - sta export.sd_data+1 - jsr export.sd_send_cmd - jmp cont_SD_SEND_CMD -cmd: .byte \1 -cont_SD_SEND_CMD: - .endm - - - -SD_RECEIVE .macro - ldx #\1 -loop_SD_RECEIVE: - phx - jsr export.spi_get -.if DEBUG - pha - jsr export.puth - PRINTS " " - pla -.endif - plx - dex - bne loop_SD_RECEIVE - pha -.if DEBUG - PRINTNL -.endif - ;; Read non-existing dummy byte for snychronization - jsr export.spi_get_nonblocking - pla - .endm - diff --git a/roms/boot/spi.asm b/roms/boot/spi.asm @@ -3,7 +3,14 @@ ;;; SPI read and write operations ;;; ;;; ----------------------------------- + +spi .namespace +.section zero_page + ;; Used by VIA for (de-)serialization +via_buffer: .byte ? +.send zero_page + ;; Wiring: ;; PA0: CS CS = %00000001 @@ -15,29 +22,28 @@ MISO = %00001000 + +.section rom + ;;; Initialize VIA: Switch all ports to output ;;; and all pins to low -.namespace export init_via: lda #$ff - sta export.via_ddra - sta export.via_ddrb + sta io.via_ddra + sta io.via_ddrb lda #$00 - sta export.via_ora - sta export.via_orb + sta io.via_ora + sta io.via_orb rts -.endn ;;; Blocking read - read until ;;; byte != $ff is read or retry counter ;;; expires. -.namespace export -spi_get: -.endn +get: .block ldy #$00 ; Try up to $ff times retry_loop: - jsr export.spi_get_nonblocking + jsr spi.get_nonblocking ;; If we read $ff, we did not receive ;; a byte. cmp #$ff @@ -45,58 +51,57 @@ retry_loop: dey ; Try again unless retry bne retry_loop ; counter expired. done: - CLEAR_BITS export.via_ora, #(MOSI|SCK) ; Set MOSI and SCK low on completion. - lda export.via_buffer + #mem.CLEAR_BITS io.via_ora, #(MOSI|SCK) ; Set MOSI and SCK low on completion. + lda spi.via_buffer rts .bend ;;; Return next byte; may be $ff in case of no transmission -.namespace export -spi_get_nonblocking: -.endn - SET_BITS export.via_ora, #MOSI ; Keep MOSI high during read +get_nonblocking: + #mem.SET_BITS io.via_ora, #MOSI ; Keep MOSI high during read lda #$00 ; Clear - sta export.via_buffer ; receive buffer. + sta spi.via_buffer ; receive buffer. ldx #$08 ; 8 bit to read. read_bits_loop: .block - asl export.via_buffer ; Make room for next bit - CLEAR_BITS export.via_ora, #SCK ; Generate clock impulse - SET_BITS export.via_ora, #SCK - lda export.via_ira ; Get next bit. + asl spi.via_buffer ; Make room for next bit + #mem.CLEAR_BITS io.via_ora, #SCK ; Generate clock impulse + #mem.SET_BITS io.via_ora, #SCK + lda io.via_ira ; Get next bit. and #MISO cmp #MISO bne cont ; Nothing to do if we got a zero bit. - inc export.via_buffer ; Set lowest bit in via_buffer + inc spi.via_buffer ; Set lowest bit in via_buffer cont: dex bne read_bits_loop - CLEAR_BITS export.via_ora, #(MOSI|SCK) ; Set MOSI and SCK low on completion. - lda export.via_buffer + #mem.CLEAR_BITS io.via_ora, #(MOSI|SCK) ; Set MOSI and SCK low on completion. + lda spi.via_buffer rts .bend ;;; Write byte via SPI -.namespace export -spi_set: -.endn +set: .block - sta export.via_buffer ; We send from via_buffer + sta spi.via_buffer ; We send from via_buffer ldx #$08 ; 8 bit to write write_bits_loop: - CLEAR_BITS export.via_ora, #SCK ; Set bits on low clock - CLEAR_BITS export.via_ora,#MOSI - lda export.via_buffer ; Get next bit to send + #mem.CLEAR_BITS io.via_ora, #SCK ; Set bits on low clock + #mem.CLEAR_BITS io.via_ora,#MOSI + lda spi.via_buffer ; Get next bit to send and #%10000000 ; Isolate bit to send. beq cont ; Set MOSI accordingly. - SET_BITS export.via_ora,#MOSI + #mem.SET_BITS io.via_ora,#MOSI jmp cont cont: - SET_BITS export.via_ora, #SCK ; Send bits on high clock - asl export.via_buffer ; Advance to next bit + #mem.SET_BITS io.via_ora, #SCK ; Send bits on high clock + asl spi.via_buffer ; Advance to next bit dex bne write_bits_loop - CLEAR_BITS export.via_ora,#SCK + #mem.CLEAR_BITS io.via_ora,#SCK rts .bend +.send rom + +.endn diff --git a/roms/boot/stack.asm b/roms/boot/stack.asm @@ -1,72 +0,0 @@ -;;; ---------------------------------------------------------- -;;; -;;; STACK -;;; -;;; ---------------------------------------------------------- - -;;; Software implementation of data stack. In difference to typical -;;; stack implementations, this stack grows from bottom to top, because -;;; we want to access eleements using indirected indexed access with -;;; the stack frame pointer as base. Therefore the stack should -;;; be initialized with the first unoccupied RAM address after the -;;; program code. -;;; -;;; PULL and PUSH do not move actual stack data, they just shift -;;; the stack pointer. -;;; -;;; Local variables on the data stack are supported by macro -;;; VAR. VAR i refers to the ith byte on the stack. PARAM allows -;;; to pass variables to a callee. PARAM i of the caller becomes -;;; VAR i of the callee. The callee should reserve stack space -;;; for both its parameters and local variables. -;;; -;;; Stack frames used for these calls are created/destroyed by -;;; subroutines create_stack_frame and delete_stack_frame. -;;; -;;; CALL is like jsr with parameter passing. There addressing -;;; modes are supported: immediate, zero-page, and local variables. -;;; For immediate and zero page, the third parameter must be lda. -;;; For local variables, the third parameter must be lda_LOCAL. -;;; See sw/stack_test/stack_test.asm for examles. - - -.namespace export -create_stack_frame: -.endn - .block - ;; Store old frame pointer on stack. - ;; Since our stack grows bottom to top, we write - ;; the data before increasing the stack pointer - #COPY_WORD_ABSOLUTE_INDIRECT export.ds_frame, (export.ds_pointer) - #PUSH $02 ; Store old frame pointer - #COPY_WORD_ABSOLUTE_INDIRECT export.ds_pointer, export.ds_frame ; Set new frame pointer - rts - .bend - -.namespace export -delete_stack_frame: -.endn - .block - #COPY_WORD_ABSOLUTE_INDIRECT export.ds_frame, export.ds_pointer ; Reset stack pointer to begin of frame. - #PULL $02 ; Move stack pointer to frame reference - #COPY_WORD_ABSOLUTE_INDIRECT (export.ds_pointer), export.ds_frame ; Restore old frame pointer. - rts - .bend - -.namespace export -push_a: -.endn - .block - sta (export.ds_pointer) - #PUSH $01 - rts - .bend - -.namespace export -pull_a: -.endn - .block - #PULL $01 - lda (export.ds_pointer) - rts - .bend diff --git a/roms/boot/stack.inc b/roms/boot/stack.inc @@ -1,77 +0,0 @@ -;;; -*- asm -*- - -;;; Macros for accessing the data stack -;;; and managing local variables and -;;; call parameters. Check stack.asm for -;;; documentation. - -;;; Stack related macros - -INIT_STACK: .macro - #STORE_WORD \1, export.ds_pointer - .endm - -PUSH: .macro ; Reserve bytes on stack (no actual push operation) - #ADD_WORD export.ds_pointer, \1 - .endm - -PULL: .macro ; Remove bytes from stack (no return value) - #SUB_WORD export.ds_pointer, \1 - .endm - -PUSH_WORD: .macro ; Push a word on the stack - lda #<\1 - sta (export.ds_pointer) - lda #>\1 - ldy #$01 - sta (export.ds_pointer),y - #PUSH $02 - .endm - -LOCAL: .macro - ldy #\1 - \2 (export.ds_frame),y - .endm -lda_LOCAL: .macro - LOCAL \1, lda - .endm -sta_LOCAL: .macro - LOCAL \1, sta - .endm -adc_LOCAL: .macro - LOCAL \1, adc - .endm -PARAM: .macro - ldy #\1 - \2 (export.ds_pointer),y - .endm -sta_PARAM: .macro - PARAM \1+2, sta - .endm -lda_PARAM: .macro - PARAM \1+2, lda - .endm - -CALL: .macro subroutine, param=[], param_lda="" - .block - .if len(\param) != 0 - .for CALL_param := 0, CALL_param < len(\param), CALL_param += $1 - \param_lda \param[CALL_param] - sta_PARAM CALL_param - .next - .endif - jsr \subroutine - .bend - .endm - -;; Push sequence of bytes to stack. Parameters: From, Length -PUSH_RANGE: .macro - ldy #$00 -loop_PUSH_RANGE: - lda \1,y - sta (ds_pointer),y - iny - cpy \2 - bne loop_PUSH_RANGE - #PUSH \2 - .endm diff --git a/roms/boot/term.asm b/roms/boot/term.asm @@ -0,0 +1,260 @@ +;;; +;;; Special commands for ANSI terminals +;;; + +term .namespace +.section rom + +;;; ANSI text attributes +plain = 0 +bold = 1 +blink = 5 +reverse = 7 + +;;; ANSI colors +black = 0 +red = 1 +green = 2 +yellow = 3 +blue = 4 +magenta = 5 +cyan = 6 +white = 7 +bright_black = 8 +bright_red = 9 +bright_green = 10 +bright_yellow = 11 +bright_blue = 12 +bright_magenta = 13 +bright_cyan = 14 +bright_white = 15 + +;;; get_screen_size +;;; Returns screen size in X, A. +;;; If not supported by terminal, C is set +;;; Input: +;;; - +;;; Output: +;;; X: Screen width +;;; A: Screen height +;;; Changes: +;;; a, x, y, c +get_screen_size: + .block + jsr ds.create_stack_frame + #ds.PUSH $02 + cursor_save_x = 0 ; Local variable + cursor_save_y = 1 ; Local variable + ;; Local variables 0 & 1: Saved cursor position + jsr term.get_cursor ; Save cursor position + bcs terminal_does_not_answer + #ds.sta_LOCAL cursor_save_y + txa + #ds.sta_LOCAL cursor_save_x + #SET_CURSOR #$FF, #$FF ; Try to move cursor to max. position + jsr term.get_cursor ; Get cursor position (= screen size) + pha ; Save it temporary + txa ; on the + pha ; hardware stack. + #ds.lda_LOCAL cursor_save_x ; Restore + tax ; old + #ds.lda_LOCAL cursor_save_y ; cursor + jsr term.set_cursor ; position + jsr ds.delete_stack_frame + pla + tax + pla + rts +terminal_does_not_answer: + jsr ds.delete_stack_frame + ldx #80 + lda #25 + rts + .bend + +clear_screen: + #io.PRINTS x"1b" .. "[2J" + rts + +set_color: + pha + #io.PRINTS x"1b" .. "[38;5;" + pla + jsr io.putd + lda #"m" + jmp io.putc + +set_background_color: + pha + #io.PRINTS x"1b" .. "[48;5;" + pla + jsr io.putd + lda #"m" + jmp io.putc + +set_text: + tax + lda #"m" + jmp send_CSI + +cursor_up: + tax + lda #"A" + jmp send_CSI + +cursor_down: + tax + lda #"B" + jmp send_CSI + +cursor_forward: + tax + lda #"C" + jmp send_CSI + +cursor_back: + tax + lda #"D" + jmp send_CSI + +scroll_up: + tax + lda #"S" + jmp send_CSI + +scroll_down: + tax + lda #"T" + jmp send_CSI + +;;; Send ANSI escape sequence to terminal. +;;; A contains command, X value +send_CSI: + pha + phx + lda #$1b + jsr io.putc + lda #"[" + jsr io.putc + pla + jsr io.putd + pla + jmp io.putc + +;;; set_cursor +;;; Sets cursor to position x, a. +;;; Position starts at 1, not 0! +;;; Input: +;;; x: x position +;;; a: y position +;;; Output: +;;; - +;;; Changes: +;;; a, x, y, c +;;; Set Cursor; x position in X, y position in A +set_cursor: + phx + pha + lda #$1b + jsr io.putc + lda #"[" + jsr io.putc + pla + jsr io.putd + lda #";" + jsr io.putc + pla + jsr io.putd + lda #"H" + jmp io.putc + +;;; get_cursor +;;; Store cursor position in x, a. +;;; Position starts at 1, not 0! +;;; Input: +;;; - +;;; Output: +;;; x: x position +;;; a: y position +;;; Changes: +;;; a, x, y, c +get_cursor: + .block + jsr ds.create_stack_frame + #ds.PUSH $08 ; Position as string + ;; We store the position string as local variables. + ;; By initializing the local variables with #$00, + ;; the strings terminate automatically when no + ;; more digits are written. + lda #$00 + .for i = 0, i < 8, i += 1 + #ds.sta_LOCAL i + .next + ;; Request cursor position + #io.PRINTS x"1b" .. "[6n" + ;; Read answer + ldx #$08 ; Number of tries + ldy #$ff ; to get an answer. +wait_for_answer: + phx + phy + jsr io.getc_nonblocking ; $1b + ply + plx + bcc terminal_answers + dey + cpy #$00 + bne wait_for_answer + dex + cpx #$00 + bne wait_for_answer + ;; Terminal does not answer. + jsr ds.delete_stack_frame + lda #$00 + ldx #$00 + sec + rts +terminal_answers: + jsr io.getc ; "[" + jsr io.getc ; First digit y + #ds.sta_LOCAL 0 + jsr io.getc ; Second digit y + cmp #";" + beq got_y_position + #ds.sta_LOCAL 1 + jsr io.getc ; Third digit y + cmp #";" + beq got_y_position + #ds.sta_LOCAL 2 + jsr io.getc ; Read and ignore terminating ';' +got_y_position: + jsr io.getc ; First digit x + #ds.sta_LOCAL 4 + jsr io.getc ; Second digit x + cmp #"R" + beq got_x_position + #ds.sta_LOCAL 5 + jsr io.getc ; Third digit x + cmp #"R" + beq got_x_position + #ds.sta_LOCAL 6 + jsr io.getc ; Read and ignore terminating 'R' +got_x_position: + ;; x position is in local variable(s) 4... + ;; y position is in local variable(s) 0... + ;; Convert them to ints + #ds.CALL io.str2byte, [0, 1, 2, 3], #ds.lda_LOCAL + #ds.lda_PARAM 0 + pha + #ds.CALL io.str2byte, [4, 5, 6, 7], #ds.lda_LOCAL + #ds.lda_PARAM 0 + pha + jsr ds.delete_stack_frame + plx + pla + clc + rts + .bend + +.send rom +.endn diff --git a/roms/boot/term.inc b/roms/boot/term.inc @@ -0,0 +1,62 @@ +;;; -*- asm -*- + +;;; ----------------------------------- +;;; +;;; ANSI Terminal +;;; +;;; ----------------------------------- + +.namespace term + +SET_COLOR .macro color + lda #color + jsr term.set_color + .endm + +SET_BACKGROUND_COLOR .macro color + lda #color + jsr term.set_background_color + .endm + +SET_TEXT .macro attribute + lda #\attribute + jsr term.set_text + .endm + +CURSOR_UP .macro steps + lda #\steps + jsr term.cursor_up + .endm + +CURSOR_DOWN .macro steps + lda #\steps + jsr term.cursor_down + .endm + +CURSOR_FORWARD .macro steps + lda #\steps + jsr term.cursor_forward + .endm + +CURSOR_BACK .macro steps + lda #\steps + jsr term.cursor_back + .endm + +SCROLL_UP .macro steps + lda #\steps + jsr term.scroll_up + .endm + +SCROLL_DOWN .macro steps + lda #\steps + jsr term.scroll_DOWN + .endm + +SET_CURSOR .macro x, y + lda \y + ldx \x + jsr term.set_cursor + .endm + +.endn diff --git a/sw/10print/10print.asm b/sw/10print/10print.asm @@ -3,25 +3,13 @@ .weak BOOT_EMBEDDED = false .endweak -.if BOOT_EMBEDDED - init_acia = export.init_acia - lfsr_init = export.lfsr_init - lfsr_step = export.lfsr_step - putc = export.putc -.else - .if SYMON - .include "boot_symon.l" - * = $0300 - .else - .include "boot.l" - * = $0200 - .endif +.if !BOOT_EMBEDDED .include "boot.inc" .endif init: cld - jsr init_acia - jsr lfsr_init + jsr io.init_acia + jsr lfsr.init jmp ten_print ten_print: @@ -34,24 +22,24 @@ l0: bne l0 dex bne l1 - jsr lfsr_step + jsr lfsr.step and #$01 bne slash .if SYMON lda #'\' - jsr putc + jsr io.putc .else - PRINTS('╲') + #io.PRINTS '╲' .endif - jsr putc + jsr io.putc jmp ten_print slash: .if SYMON lda #'/' - jsr putc + jsr io.putc .else - PRINTS('╱') + #io.PRINTS '╱' .endif - jsr putc + jsr io.putc jmp ten_print .bend diff --git a/sw/ansi_test/ansi_test.asm b/sw/ansi_test/ansi_test.asm @@ -1,25 +1,14 @@ -.if SYMON - .include "boot_symon.l" - start_address = $0300 -.else - .include "boot.l" - start_address = $0200 -.endif .include "boot.inc" - * = rom_zero_page_end - .dsection zero_page - * = start_address - .dsection code - .cerror * > $8000, "RAM exhausted" +.dsection code .section code start_of_stack = end_of_code ; Stack starts right after code init: cld - jsr init_acia - INIT_STACK start_of_stack + jsr io.init_acia + #ds.INIT_STACK start_of_stack ;; Termin program on PC needs some time to start up - ldy #$80 + ldy #$ff ldx #$ff delay: dex @@ -27,115 +16,120 @@ delay: dey bne delay jsr ansi_test - jsr getc + jsr io.getc jsr print_all_colors -.if false -.endif -end: - jmp end + jsr io.getc + jmp init ansi_test: .block - jsr create_stack_frame - jsr clear_screen - #SET_CURSOR #$01, #$01 - #PRINTSNL "ANSI Terminal" - #SET_CURSOR #$03, #$02 - PRINTS "Text starting at position 3, 2" - #SET_CURSOR #$02, #$03 - PRINTSNL "Text starting at position 2, 3" - PRINTS "Cursor position: " - jsr get_cursor + jsr ds.create_stack_frame + jsr term.clear_screen + #term.SET_CURSOR #$01, #$01 + #io.PRINTSNL "ANSI Terminal" + #term.SET_CURSOR #$03, #$02 + #io.PRINTS "Text starting at position 3, 2" + #term.SET_CURSOR #$02, #$03 + #io.PRINTSNL "Text starting at position 2, 3" + #io.PRINTS "Cursor position: " + jsr term.get_cursor pha txa - jsr putd - PRINTS ", " + jsr io.putd + #io.PRINTS ", " pla - jsr putd - #SET_CURSOR #$01, #$05 - PRINTS "Screen size: " - jsr get_screen_size + jsr io.putd + #term.SET_CURSOR #$01, #$05 + #io.PRINTS "Screen size: " + jsr term.get_screen_size pha txa - jsr putd - PRINTS ", " + jsr io.putd + #io.PRINTS ", " pla - jsr putd - PRINTNL - #SET_TEXT bold - PRINTSNL "Bold text" - #SET_TEXT plain - #SET_TEXT blink - PRINTSNL "Blinking text" - #SET_TEXT plain - #SET_TEXT reverse - PRINTSNL "Reverse text" - #SET_TEXT plain + jsr io.putd + jsr io.putnl + #term.SET_TEXT term.bold + #io.PRINTSNL "Bold text" + #term.SET_TEXT term.plain + #term.SET_TEXT term.blink + #io.PRINTSNL "Blinking text" + #term.SET_TEXT term.plain + #term.SET_TEXT term.reverse + #io.PRINTSNL "Reverse text" + #term.SET_TEXT term.plain lda #"*" - jsr putc - #CURSOR_DOWN 1 - #CURSOR_BACK 1 + jsr io.putc + #term.CURSOR_DOWN 1 + #term.CURSOR_BACK 1 lda #"*" - jsr putc - #CURSOR_DOWN 1 - #CURSOR_BACK 1 + jsr io.putc + #term.CURSOR_DOWN 1 + #term.CURSOR_BACK 1 lda #"*" - jsr putc - #CURSOR_FORWARD 1 + jsr io.putc + #term.CURSOR_FORWARD 1 lda #"*" - jsr putc - #CURSOR_BACK 1 - #CURSOR_UP 1 + jsr io.putc + #term.CURSOR_BACK 1 + #term.CURSOR_UP 1 lda #"*" - jsr putc - #CURSOR_BACK 1 - #CURSOR_UP 1 + jsr io.putc + #term.CURSOR_BACK 1 + #term.CURSOR_UP 1 lda #"*" - jsr putc + jsr io.putc lda #$03 - jsr cursor_down + jsr term.cursor_down lda #$03 - jsr cursor_back - PRINTSNL "ANSI test completed." + jsr term.cursor_back + #io.PRINTSNL "ANSI test completed." + jsr ds.delete_stack_frame rts .bend print_all_colors: .block - jsr clear_screen - .for color in black, red, green, yellow, blue, magenta, cyan, white - #SET_COLOR color - PRINTSNL "Foreground color" + jsr ds.create_stack_frame + jsr term.clear_screen + #term.SET_CURSOR #$01, #$01 + .for color in (term.black, term.red, term.green, term.yellow, + term.blue, term.magenta, term.cyan, term.white) + #term.SET_COLOR color + #io.PRINTSNL "Foreground color" .next - #SET_TEXT plain - .for color in black, red, green, yellow, blue, magenta, cyan, white - #SET_BACKGROUND_COLOR color - PRINTS "Background color" - #SET_TEXT plain - PRINTNL + #term.SET_TEXT term.plain + .for color in (term.black, term.red, term.green, term.yellow, + term.blue, term.magenta, term.cyan, term.white) + #term.SET_BACKGROUND_COLOR color + #io.PRINTS "Background color" + #term.SET_TEXT term.plain + jsr io.putnl .next - .for color in (bright_black, bright_red, bright_green, bright_yellow, - bright_blue, bright_magenta, bright_cyan, bright_white) - #SET_COLOR color - PRINTSNL "Foreground color" + .for color in (term.bright_black, term.bright_red, + term.bright_green, term.bright_yellow, + term.bright_blue, term.bright_magenta, + term.bright_cyan, term.bright_white) + #term.SET_COLOR color + #io.PRINTSNL "Foreground color" .next lda #$00 loop: pha - jsr set_color + jsr term.set_color pla pha - jsr putd + jsr io.putd lda #" " - jsr putc + jsr io.putc pla - pha inc a cmp #$00 bne loop - PRINTNL - jsr delete_stack_frame - #SET_TEXT plain + jsr io.putnl + jsr ds.delete_stack_frame + #term.SET_TEXT term.plain + #io.PRINTSNL "Color test completed." rts .bend diff --git a/sw/interrupts/interrupts.asm b/sw/interrupts/interrupts.asm @@ -77,7 +77,7 @@ loop: jsr getc lda flag jsr puth - PRINTNL + #PRINTNL jmp loop .bend diff --git a/sw/load_from_card/load_from_card.asm b/sw/load_from_card/load_from_card.asm @@ -4,32 +4,11 @@ .weak BOOT_EMBEDDED = false .endweak -.if BOOT_EMBEDDED - init_acia = export.init_acia - init_via = export.init_via - getc = export.getc - putc = export.putc - create_stack_frame = export.create_stack_frame - ds_pointer = export.ds_pointer - sd_data = export.sd_data - sd_read_block = export.sd_read_block - sd_open = export.sd_open - puts_str = export.puts_str - puts = export.puts - puth = export.puth -.else - .if SYMON - .include "boot_symon.l" - start_address = $0300 - .else - .include "boot.l" - start_address = $0200 - .endif +.if !BOOT_EMBEDDED .include "boot.inc" - * = rom_zero_page_end - .dsection zero_page - * = start_address .endif + + .dsection code .section code @@ -44,15 +23,17 @@ init: .block .if SYMON cld - jsr init_acia - jsr init_via + jsr io.init_acia + jsr spi.init_via .endif .if !BOOT_EMBEDDED ;; Wait for key to start - jsr getc + jsr io.getc .endif - INIT_STACK $7fff-$0400 + #ds.INIT_STACK $7fff-$0400 loop: + #io.PRINTSNL "***** Eris 2010 8-Bit System *****" + #io.PRINTNL jsr ls jsr choose_program bcs loop @@ -63,8 +44,8 @@ loop: load_address = $0200 choose_program: - PRINTSNL("Choose program (0-9). Any other key reloads card.") - jsr getc + #io.PRINTSNL "Choose program (0-9). Any other key reloads card." + jsr io.getc sec sbc #'0' cmp #$0a ; Sets carry if not a digit @@ -74,44 +55,45 @@ choose_program: execute: .block pha - jsr create_stack_frame - PUSH 4 ; Local variables + jsr ds.create_stack_frame + #ds.PUSH 4 ; Local variables pla ;; Each app has 2**16 blocks, app number is in A, therefore ;; the address of the app is [#$00, A, #$00, #$01] - sta_LOCAL 1 - PRINTS "Executing program " - lda_LOCAL 1 + #ds.sta_LOCAL 1 + #io.PRINTS "Loading and executing program " + #ds.lda_LOCAL 1 clc adc #'0' - jsr putc - PRINTSNL "." + jsr io.putc + #io.PRINTSNL "." lda #$00 - sta_LOCAL 0 - sta_LOCAL 2 + #ds.sta_LOCAL 0 + #ds.sta_LOCAL 2 lda #$01 - sta_LOCAL 3 - COPY_WORD_ABSOLUTE_INDIRECT ds_pointer, sd_data ; Read block - PUSH $0200 ; to stack - CALL sd_read_block, [0, 1, 2, 3], lda_LOCAL - PULL $0200 ; Reset stack pointer to block read - COPY_WORD_IMMEDIATE load_address, sd_data ; Set Target address - lda (ds_pointer) ; Number of blocks + #ds.sta_LOCAL 3 + #mem.COPY_WORD_ABSOLUTE_INDIRECT ds.ptr, sd.data ; Read block + #ds.PUSH $0200 ; to stack + #ds.CALL sd.read_block, [0, 1, 2, 3], #ds.lda_LOCAL + #ds.PULL $0200 ; Reset stack pointer to block read + #mem.COPY_WORD_IMMEDIATE load_address, sd.data ; Set Target address + lda (ds.ptr) ; Number of blocks read_next_block: pha ;; Advance to next block on card clc - lda_LOCAL 3 + #ds.lda_LOCAL 3 adc #$01 - sta_LOCAL 3 - lda_LOCAL 2 + #ds.sta_LOCAL 3 + #ds.lda_LOCAL 2 adc #$00 - sta_LOCAL 2 - CALL sd_read_block, [0, 1, 2, 3], lda_LOCAL ; Read block - ADD_WORD sd_data, $0200 ; Advance to next block + #ds.sta_LOCAL 2 + #ds.CALL sd.read_block, [0, 1, 2, 3], #ds.lda_LOCAL ; Read block + #mem.ADD_WORD sd.data, $0200 ; Advance to next block pla dec a bne read_next_block + jsr ds.delete_stack_frame ;; Done. Execute program jmp load_address .bend @@ -120,14 +102,14 @@ read_next_block: ;; List programs on card ls: .block - jsr create_stack_frame - jsr sd_open + jsr ds.create_stack_frame + jsr sd.open ;; List files on card - COPY_WORD_ABSOLUTE_INDIRECT ds_pointer, sd_data ; Read block - PUSH $0200 ; to stack - CALL sd_read_block, [#$00, #$00, #$00, #$00], lda - PULL $0200 ; Reset stack pointer to point to block read - lda (ds_pointer) + #mem.COPY_WORD_ABSOLUTE_INDIRECT ds.ptr, sd.data ; Read block + #ds.PUSH $0200 ; to stack + #ds.CALL sd.read_block, [#$00, #$00, #$00, #$00], lda + #ds.PULL $0200 ; Reset stack pointer to point to block read + lda (ds.ptr) cmp #$00 ; Check FS version beq cont jmp not_supported @@ -137,43 +119,43 @@ dir_entry_loop: pha clc adc #'0' - jsr putc - PRINTS ": " + jsr io.putc + #io.PRINTS ": " ;; Each app has 2**16 blocks, therefore ;; the address of app i is [#$00, #i, #$00, #$01] lda #$00 - sta_LOCAL 0 - sta_LOCAL 2 + #ds.sta_LOCAL 0 + #ds.sta_LOCAL 2 lda #$01 - sta_LOCAL 3 + #ds.sta_LOCAL 3 pla pha - sta_LOCAL 1 - PUSH 4 - COPY_WORD_ABSOLUTE_INDIRECT ds_pointer, sd_data ; Read block - PUSH $0200 ; to stack - CALL sd_read_block, [0, 1, 2, 3], lda_LOCAL - PULL $0200 ; Reset stack pointer to block read - lda (ds_pointer) ; Number of blocks + #ds.sta_LOCAL 1 + #ds.PUSH 4 + #mem.COPY_WORD_ABSOLUTE_INDIRECT ds.ptr, sd.data ; Read block + #ds.PUSH $0200 ; to stack + #ds.CALL sd.read_block, [0, 1, 2, 3], #ds.lda_LOCAL + #ds.PULL $0200 ; Reset stack pointer to block read + lda (ds.ptr) ; Number of blocks beq filename_printed ; This spot is not occupied pha - COPY_WORD_ABSOLUTE_INDIRECT ds_pointer, puts_str - ADD_WORD puts_str, $01 ; Start of filename - jsr puts - PRINTS " ($" + #mem.COPY_WORD_ABSOLUTE_INDIRECT ds.ptr, io.puts_str + #mem.ADD_WORD io.puts_str, $01 ; Start of filename + jsr io.puts + #io.PRINTS " (" pla pha - jsr puth + jsr io.putd pla cmp #$01 beq one_block - PRINTS " blocks)" + #io.PRINTS " blocks)" jmp filename_printed one_block: - PRINTS " block)" + #io.PRINTS " block)" filename_printed: - PRINTNL - PULL 4 + jsr io.putnl + #ds.PULL 4 pla inc a cmp #$0a @@ -181,12 +163,12 @@ filename_printed: jmp dir_entry_loop done: clc - jsr export.delete_stack_frame + jsr ds.delete_stack_frame rts not_supported: - PRINTSNL "This filesystem is not supported." + #io.PRINTSNL "This filesystem is not supported." sec - jsr export.delete_stack_frame + jsr ds.delete_stack_frame rts .bend diff --git a/sw/serial_line_echo/serial_line_echo.asm b/sw/serial_line_echo/serial_line_echo.asm @@ -1,17 +1,11 @@ -.if SYMON - .include "boot_symon.l" -.else - .include "boot.l" -.endif .include "boot.inc" - * = $0200 init: - jsr init_acia + jsr io.init_acia loop: - #PRINTSNL "Serial line echo" - #INPUTS $1000, #$10 - #PRINTNL - #PRINT $1000 - #PRINTNL + #io.PRINTSNL "Serial line echo" + #io.INPUTS $1000, #$10 + jsr io.putnl + #io.PRINT $1000 + jsr io.putnl jmp loop diff --git a/sw/stack_test/stack_test.asm b/sw/stack_test/stack_test.asm @@ -1,17 +1,7 @@ ;;; A data stack -.if SYMON - .include "boot_symon.l" - start_address = $0300 -.else - .include "boot.l" - start_address = $0200 -.endif .include "boot.inc" - * = start_address .dsection code - .cerror * > $8000, "RAM exhausted" - .section code ;; start_of_stack = $7fff-$206+$1 ; Minimal stack as defined in ROM @@ -19,11 +9,11 @@ init: .block cld - INIT_STACK start_of_stack - jsr init_acia + #ds.INIT_STACK start_of_stack + jsr io.init_acia .if SYMON .else - jsr getc + jsr io.getc .endif jsr stack_test jsr test_local_variables @@ -37,85 +27,85 @@ loop: stack_test: .block ;; Testing empty stack - jsr create_stack_frame - jsr delete_stack_frame - lda ds_pointer + jsr ds.create_stack_frame + jsr ds.delete_stack_frame + lda ds.ptr cmp #<start_of_stack #CHECK_ERROR - lda ds_pointer+1 + lda ds.ptr+1 cmp #>start_of_stack #CHECK_ERROR ;; Push and pull - jsr create_stack_frame + jsr ds.create_stack_frame lda #$a0 - sta (ds_pointer) - PUSH $01 + sta (ds.ptr) + #ds.PUSH $01 lda #$b0 - sta (ds_pointer) - PUSH $01 + sta (ds.ptr) + #ds.PUSH $01 lda #$c0 - sta (ds_pointer) - PUSH $01 - PULL $01 - lda (ds_pointer) + sta (ds.ptr) + #ds.PUSH $01 + #ds.PULL $01 + lda (ds.ptr) cmp #$c0 #CHECK_ERROR - PULL $01 - lda (ds_pointer) + #ds.PULL $01 + lda (ds.ptr) cmp #$b0 #CHECK_ERROR - PULL $01 - lda (ds_pointer) + #ds.PULL $01 + lda (ds.ptr) cmp #$a0 #CHECK_ERROR - PUSH $01 + #ds.PUSH $01 ;; Push and pull with new frame lda #$a1 - sta (ds_pointer) - PUSH $01 - lda ds_pointer ; Save ds_pointer + sta (ds.ptr) + #ds.PUSH $01 + lda ds.ptr ; Save stack pointer pha ; for later comparison - jsr create_stack_frame + jsr ds.create_stack_frame ldy #$00 lda #$b1 - sta (ds_pointer),y + sta (ds.ptr),y inc y - sta (ds_pointer),y + sta (ds.ptr),y inc y - sta (ds_pointer),y + sta (ds.ptr),y inc y - PUSH $03 - PULL $01 - lda (ds_pointer) + #ds.PUSH $03 + #ds.PULL $01 + lda (ds.ptr) cmp #$b1 #CHECK_ERROR - jsr delete_stack_frame - pla ; Still same ds_pointer - cmp ds_pointer ; as before creating and + jsr ds.delete_stack_frame + pla ; Still same stack pointer + cmp ds.ptr ; as before creating and #CHECK_ERROR ; deleting frame? - PULL $01 - lda (ds_pointer) + #ds.PULL $01 + lda (ds.ptr) cmp #$a1 #CHECK_ERROR - PULL $01 - lda (ds_pointer) + #ds.PULL $01 + lda (ds.ptr) cmp #$a0 #CHECK_ERROR - jsr delete_stack_frame - lda ds_pointer ; Stack should be + jsr ds.delete_stack_frame + lda ds.ptr ; Stack should be cmp #<start_of_stack ; empty again. #CHECK_ERROR - lda ds_pointer+1 + lda ds.ptr+1 cmp #>start_of_stack #CHECK_ERROR - #PUSH_WORD $abcd - jsr pull_a + #ds.PUSH_WORD $abcd + jsr ds.pull_a cmp #$ab #CHECK_ERROR - jsr pull_a + jsr ds.pull_a cmp #$cd #CHECK_ERROR - PRINTSNL("Stack test completed!") + #io.PRINTSNL "Stack test completed!" rts .bend @@ -123,7 +113,7 @@ CHECK_ERROR: .macro .block beq error_cont error: - PRINTSNL("Error!") + #io.PRINTSNL "Error!" error_loop: jmp error_loop error_cont: @@ -132,86 +122,86 @@ error_cont: test_local_variables: .block - jsr create_stack_frame + jsr ds.create_stack_frame ;; Working with local variables - PUSH $02 ; Create local variables + #ds.PUSH $02 ; Create local variables lda #$ab - sta_LOCAL 0 + #ds.sta_LOCAL 0 lda #$00 - lda_LOCAL 0 + #ds.lda_LOCAL 0 inc a - sta_LOCAL 1 + #ds.sta_LOCAL 1 lda #$00 - lda_LOCAL 1 + #ds.lda_LOCAL 1 cmp #$ac #CHECK_ERROR ;; Passing paramters lda #$01 - sta_PARAM 0 + #ds.sta_PARAM 0 lda #$02 - sta_PARAM 1 + #ds.sta_PARAM 1 jsr test_param - lda_PARAM 0 + #ds.lda_PARAM 0 cmp #$03 #CHECK_ERROR - jsr delete_stack_frame - PRINTSNL("Local variable test completed!") + jsr ds.delete_stack_frame + #io.PRINTSNL "Local variable test completed!" rts .bend test_param: .block - jsr create_stack_frame - PUSH $02 ; Local variables (here: parameters) - lda_LOCAL 0 + jsr ds.create_stack_frame + #ds.PUSH $02 ; Local variables (here: parameters) + #ds.lda_LOCAL 0 clc - adc_LOCAL 1 - sta_LOCAL 0 - jsr delete_stack_frame + #ds.adc_LOCAL 1 + #ds.sta_LOCAL 0 + jsr ds.delete_stack_frame rts .bend test_recursion: .block - jsr create_stack_frame - PUSH $02 ; Create local variables + jsr ds.create_stack_frame + #ds.PUSH $02 ; Create local variables lda #$04 ; Recursion counter - sta_LOCAL 0 + #ds.sta_LOCAL 0 lda #$01 ; Initial value - sta_LOCAL 1 - CALL recursion, [0, 1], lda_LOCAL - lda_PARAM 1 ; Check for + #ds.sta_LOCAL 1 + #ds.CALL recursion, [0, 1], #ds.lda_LOCAL + #ds.lda_PARAM 1 ; Check for cmp #$09 ; expected result #CHECK_ERROR - jsr delete_stack_frame + jsr ds.delete_stack_frame ;; Check if stack is empty again - lda ds_pointer + lda ds.ptr cmp #<start_of_stack #CHECK_ERROR - lda ds_pointer+1 + lda ds.ptr+1 cmp #>start_of_stack #CHECK_ERROR - PRINTSNL("Recursion test completed!") + #io.PRINTSNL "Recursion test completed!" rts .bend recursion: .block - jsr create_stack_frame - PUSH $02 ; Local variables - lda_LOCAL 0 + jsr ds.create_stack_frame + #ds.PUSH $02 ; Local variables + #ds.lda_LOCAL 0 beq done dec a - sta_LOCAL 0 - lda_LOCAL 1 + #ds.sta_LOCAL 0 + #ds.lda_LOCAL 1 inc a inc a - sta_LOCAL 1 - CALL recursion, [0, 1], lda_LOCAL - lda_PARAM 1 - sta_LOCAL 1 + #ds.sta_LOCAL 1 + #ds.CALL recursion, [0, 1], #ds.lda_LOCAL + #ds.lda_PARAM 1 + #ds.sta_LOCAL 1 done: - jsr delete_stack_frame + jsr ds.delete_stack_frame rts .bend diff --git a/sw/ttt/README.txt b/sw/ttt/README.txt @@ -1,13 +1,11 @@ * Targets ttt.bin - is the binary to be uploaded to address $300 on the GATE 2010 + is the binary to be uploaded to address $200 on the Eris 2010 ttt_symon.bin is the binary for Symon (ROM & ACIA at different memory addresses) -*_boot.bin - are binaries to be included into the boot ROM of GATE 2010 and Symon *_test.bin - are binaries running self-tests on GATE 2010 and Symon + are binaries running self-tests on Eris 2010 and Symon * Source Code diff --git a/sw/ttt/board.asm b/sw/ttt/board.asm @@ -33,7 +33,7 @@ game_finished: jsr print_board pla jsr print_game_state - PRINTNL + jsr io.putnl rts next_ply: cmp #piece_x @@ -291,7 +291,7 @@ SET_FIELD .macro .endm GET_FIELD .macro - #STORE_WORD \1, board_ptr + #mem.STORE_WORD \1, board_ptr ldx #\2 jsr get_field .endm @@ -305,23 +305,23 @@ print_board: .block ldx #$ff phx - #PRINTSNL '+---+---+---+' + #io.PRINTSNL '+---+---+---+' print_field: lda #$03 sta tmp ; Print each line 3 times print_line: lda #'|' - jsr putc + jsr io.putc plx inx phx jsr get_field jsr piece_to_ascii - jsr putc + jsr io.putc plx phx jsr put_field_number_if_empty_and_middle - jsr putc + jsr io.putc plx phx cpx #$02 @@ -338,7 +338,7 @@ check_if_all_rows_printed: plx ; Clean-up stack rts print_row_seperator: - #PRINTSNL '|' + #io.PRINTSNL '|' dec tmp ; Check if each line has been printed 3 times lda tmp beq print_seperator @@ -348,7 +348,7 @@ print_row_seperator: pha jmp print_line ;again. print_seperator: - #PRINTSNL '+---+---+---+' + #io.PRINTSNL '+---+---+---+' lda #$03 sta tmp jmp check_if_all_rows_printed @@ -366,12 +366,12 @@ put_field_number_if_empty_and_middle: txa clc adc #'1' - jsr putc + jsr io.putc pla rts print_verbatim: pla - jmp putc + jmp io.putc .bend @@ -575,18 +575,18 @@ print_game_state: beq somebody_won cmp #piece_none bne no_draw - #PRINTSNL "Draw!" + #io.PRINTSNL "Draw!" rts no_draw: - #PRINTSNL "Let the game continue!" + #io.PRINTSNL "Let the game continue!" rts somebody_won: pha - #PRINTS "Player " + #io.PRINTS "Player " pla clc adc #'0' - jsr putc - #PRINTSNL " wins!" + jsr io.putc + #io.PRINTSNL " wins!" rts .bend diff --git a/sw/ttt/board_test.asm b/sw/ttt/board_test.asm @@ -3,7 +3,7 @@ CHECK_ERROR .macro cmp #\1 beq no_error - #PRINTSNL "Error" + #io.PRINTSNL "Error" stop_loop jmp stop_loop no_error @@ -137,6 +137,6 @@ game_board_test: #PLAYER_WIN_FIRST_DIAGONAL piece_x #PLAYER_WIN_SECOND_DIAGONAL piece_o #PLAYER_WIN_FIRST_DIAGONAL piece_o - #PRINTSNL "Board tests completed. No errors found!" + #io.PRINTSNL "Board tests completed. No errors found!" rts .bend diff --git a/sw/ttt/computer_player.asm b/sw/ttt/computer_player.asm @@ -15,8 +15,8 @@ computer_random_ply: ;; nibble until it is <= 8. ;; BUG: Looks like we never get 0. get_random: - jsr lfsr_step - lda lfsr_state + jsr lfsr.step + lda lfsr.state and #$0f cmp #$09 bcs get_random @@ -127,7 +127,7 @@ computer_perfect_ply: pla bcc execute_ply ;; No rule left; this should not happen. - #PRINTSNL 'Error' + #io.PRINTSNL 'Error' error: jmp error execute_ply: @@ -232,12 +232,12 @@ win_column: ;; We mirror the board in order to use ;; win_column to check for a winning ;; position. - #STORE_WORD board_mirrored,other_board_ptr + #mem.STORE_WORD board_mirrored,other_board_ptr jsr mirror_board - #STORE_WORD board_mirrored,board_ptr + #mem.STORE_WORD board_mirrored,board_ptr lda tmp ; Who am I? jsr win_row - #STORE_WORD main_board,board_ptr + #mem.STORE_WORD main_board,board_ptr bcs no_win ;; We found a winning position ;; since we found the winning @@ -360,7 +360,7 @@ fork: ;; an empty field after pairing, then this is the ;; fork field. pha ; Remember who I am - #STORE_WORD fork_board_rows, other_board_ptr + #mem.STORE_WORD fork_board_rows, other_board_ptr pla ; Store my piece pha ; in A jsr find_rows_for_fork @@ -369,25 +369,25 @@ fork: ;; find_rows_for_fork again. ;; We use board_mirrored as an auxillary variable ;; here. - #STORE_WORD main_board, board_ptr - #STORE_WORD fork_board_columns, other_board_ptr + #mem.STORE_WORD main_board, board_ptr + #mem.STORE_WORD fork_board_columns, other_board_ptr jsr mirror_board ;; Check for fork points on mirrored ;; board and store the result in ;; fork_board_columns - #STORE_WORD fork_board_columns, board_ptr - #STORE_WORD board_mirrored, other_board_ptr + #mem.STORE_WORD fork_board_columns, board_ptr + #mem.STORE_WORD board_mirrored, other_board_ptr pla ; Store my piece pha ; in A jsr find_rows_for_fork ;; Reverse mirroring - #STORE_WORD board_mirrored, board_ptr - #STORE_WORD fork_board_columns, other_board_ptr + #mem.STORE_WORD board_mirrored, board_ptr + #mem.STORE_WORD fork_board_columns, other_board_ptr jsr mirror_board pla pha - #STORE_WORD fork_board_rows, board_ptr - #STORE_WORD fork_board_columns, other_board_ptr + #mem.STORE_WORD fork_board_rows, board_ptr + #mem.STORE_WORD fork_board_columns, other_board_ptr jsr check_fork bcs cont jmp done @@ -410,8 +410,8 @@ cont: sta fork_board_diagonals sta fork_board_diagonals+1 sta fork_board_diagonals+2 - #STORE_WORD main_board, board_ptr - #STORE_WORD fork_board_diagonals, other_board_ptr + #mem.STORE_WORD main_board, board_ptr + #mem.STORE_WORD fork_board_diagonals, other_board_ptr #COPY_FIELD 0, 0 #COPY_FIELD 4, 1 #COPY_FIELD 8, 2 @@ -419,8 +419,8 @@ cont: #COPY_FIELD 2, 3 #COPY_FIELD 4, 4 #COPY_FIELD 6, 5 - #STORE_WORD fork_board_diagonals, board_ptr - #STORE_WORD board_mirrored, other_board_ptr + #mem.STORE_WORD fork_board_diagonals, board_ptr + #mem.STORE_WORD board_mirrored, other_board_ptr pla ; Store my piece pha ; in A jsr find_rows_for_fork @@ -432,8 +432,8 @@ cont: lda #%00110011 sta fork_board_diagonals+1 ;; First diagonal - #STORE_WORD board_mirrored, board_ptr - #STORE_WORD fork_board_diagonals, other_board_ptr + #mem.STORE_WORD board_mirrored, board_ptr + #mem.STORE_WORD fork_board_diagonals, other_board_ptr #COPY_FIELD 0, 0 #COPY_FIELD 1, 4 #COPY_FIELD 2, 8 @@ -445,21 +445,21 @@ cont: #GET_FIELD board_mirrored, 4 cmp #$00 bne middle_field_not_part_of_potential_fork - #STORE_WORD fork_board_diagonals, board_ptr + #mem.STORE_WORD fork_board_diagonals, board_ptr #SET_FIELD $00, 4 middle_field_not_part_of_potential_fork: ;; No check if there is a fork between ;; rows and diagonals ... - #STORE_WORD fork_board_diagonals, board_ptr - #STORE_WORD fork_board_rows, other_board_ptr + #mem.STORE_WORD fork_board_diagonals, board_ptr + #mem.STORE_WORD fork_board_rows, other_board_ptr jsr check_fork bcc done ;; ... and columns and diagonals. - #STORE_WORD fork_board_columns, other_board_ptr + #mem.STORE_WORD fork_board_columns, other_board_ptr jsr check_fork done: ;; Some restore operatons - #STORE_WORD main_board, board_ptr + #mem.STORE_WORD main_board, board_ptr pla rts .bend diff --git a/sw/ttt/computer_player_test.asm b/sw/ttt/computer_player_test.asm @@ -42,7 +42,7 @@ check_board_cont: mirror_board_test: .block jsr init_board - #STORE_WORD board_mirrored,other_board_ptr + #mem.STORE_WORD board_mirrored,other_board_ptr ;; Test rotation of board ;; One piece on field 0. ;; Rotation should change nothing @@ -66,10 +66,10 @@ mirror_board_test: jsr mirror_board #CHECK_BOARD %011100,%100001,%011110 no_error: - #PRINTSNL "OK" + #io.PRINTSNL "OK" rts error: - #PRINTSNL "ERROR" + #io.PRINTSNL "ERROR" rts .bend @@ -127,7 +127,7 @@ win_by_column: rts play_win_by_column: jsr print_board - PRINTNL + jsr io.putnl lda #piece_x jsr computer_perfect_ply pha @@ -136,10 +136,10 @@ play_win_by_column: jsr get_game_state cmp #piece_x bne win_by_column_error - #PRINTSNL "OK" + #io.PRINTSNL "OK" rts win_by_column_error: - #PRINTSNL "ERROR" + #io.PRINTSNL "ERROR" rts win_by_diagonal: @@ -188,7 +188,7 @@ win_by_diagonal: rts play_win_by_diagonal: jsr print_board - #PRINTNL + jsr io.putnl lda #piece_x jsr computer_perfect_ply pha @@ -197,10 +197,10 @@ play_win_by_diagonal: jsr get_game_state cmp #piece_x bne win_by_diagonal_error - #PRINTSNL "OK" + #io.PRINTSNL "OK" rts win_by_diagonal_error: - #PRINTSNL "ERROR" + #io.PRINTSNL "ERROR" rts block_by_column: @@ -255,13 +255,13 @@ block_by_column: rts play_block_by_column: jsr print_board - #PRINTNL + jsr io.putnl lda #piece_o jsr computer_perfect_ply pha jsr print_board pla - jsr getc + jsr io.getc rts fork_row_column: @@ -277,7 +277,7 @@ fork_row_column: pha jsr print_board pla - #PRINTNL + jsr io.putnl lda #piece_o jsr computer_perfect_ply pha @@ -286,30 +286,30 @@ fork_row_column: ;; Check for correct ply #GET_FIELD main_board,5 #CHECK_ERROR piece_o - jsr getc + jsr io.getc ;; Row/diagonal fork jsr init_board ;; lda #$ac ; Test runs perfectly with this initialization of the lfsr - ;; sta lfsr_state - ;; sta lfsr_state+1 + ;; sta lfsr.state + ;; sta lfsr.state+1 jsr computer_perfect_init #SET_FIELD piece_x, 0 #SET_FIELD piece_o, 3 #SET_FIELD piece_x, 6 - #PRINTNL + jsr io.putnl pha jsr print_board pla lda #piece_x jsr computer_perfect_ply pha - #PRINTNL + jsr io.putnl jsr print_board pla ;; Check for correct ply #GET_FIELD main_board,2 #CHECK_ERROR piece_x - jsr getc + jsr io.getc ;; Another Row/diagonal fork jsr init_board jsr computer_perfect_init @@ -321,7 +321,7 @@ fork_row_column: pha jsr print_board pla - #PRINTNL + jsr io.putnl lda #piece_o jsr computer_perfect_ply pha @@ -330,32 +330,32 @@ fork_row_column: ;; Check for correct ply #GET_FIELD main_board,4 #CHECK_ERROR piece_o - jsr getc + jsr io.getc rts .bend test_block_fork: .block jsr computer_perfect_init - #STORE_WORD main_board,board_ptr + #mem.STORE_WORD main_board,board_ptr #SET_FIELD piece_x, 0 #SET_FIELD piece_o, 3 #SET_FIELD piece_x, 4 #SET_FIELD piece_o, 8 - #PRINTNL + jsr io.putnl pha jsr print_board pla lda #piece_o jsr computer_perfect_ply pha - #PRINTNL + jsr io.putnl jsr print_board pla ;; Check for correct ply #GET_FIELD main_board,1 #CHECK_ERROR piece_o - jsr getc + jsr io.getc ;; Check if computer creates ;; two-in-a-row/column/diagonal ;; when when a fork by the opponet is @@ -366,48 +366,48 @@ test_block_fork: ;; O -> 1 ;; X -> 9 jsr computer_perfect_init - #STORE_WORD main_board,board_ptr + #mem.STORE_WORD main_board,board_ptr #SET_FIELD piece_o, 0 #SET_FIELD piece_x, 4 #SET_FIELD piece_x, 8 - #PRINTNL + jsr io.putnl pha jsr print_board pla lda #piece_o jsr computer_perfect_ply pha - #PRINTNL + jsr io.putnl jsr print_board pla ;; Check for correct ply #GET_FIELD main_board,1 #CHECK_ERROR piece_o - jsr getc + jsr io.getc ;; The following scenario ;; can be created by the plys ;; X -> 1 ;; O -> 5 ;; X -> 9 jsr computer_perfect_init - #STORE_WORD main_board,board_ptr + #mem.STORE_WORD main_board,board_ptr #SET_FIELD piece_x, 0 #SET_FIELD piece_o, 4 #SET_FIELD piece_x, 8 - #PRINTNL + jsr io.putnl pha jsr print_board pla lda #piece_o jsr computer_perfect_ply pha - #PRINTNL + jsr io.putnl jsr print_board pla ;; Check for correct ply #GET_FIELD main_board,3 #CHECK_ERROR piece_o - jsr getc + jsr io.getc rts ;; The following scenario ;; can be created by the plys @@ -415,70 +415,70 @@ test_block_fork: ;; O -> 1 ;; X -> 9 jsr computer_perfect_init - #STORE_WORD main_board,board_ptr + #mem.STORE_WORD main_board,board_ptr #SET_FIELD piece_x, 4 #SET_FIELD piece_o, 0 #SET_FIELD piece_x, 8 - #PRINTNL + jsr io.putnl pha jsr print_board pla lda #piece_o jsr computer_perfect_ply pha - #PRINTNL + jsr io.putnl jsr print_board pla ;; Check for correct ply #GET_FIELD main_board,2 #CHECK_ERROR piece_o - jsr getc + jsr io.getc rts .bend test_play_opposite_corner: .block jsr computer_perfect_init - #STORE_WORD main_board,board_ptr + #mem.STORE_WORD main_board,board_ptr #SET_FIELD piece_x, 0 #SET_FIELD piece_o, 4 - #PRINTNL + jsr io.putnl pha jsr print_board pla lda #piece_o jsr computer_perfect_ply pha - #PRINTNL + jsr io.putnl jsr print_board pla ;; Check for correct ply #GET_FIELD main_board,8 #CHECK_ERROR piece_o - jsr getc + jsr io.getc rts .bend test_play_empty_corner: .block jsr computer_perfect_init - #STORE_WORD main_board,board_ptr + #mem.STORE_WORD main_board,board_ptr #SET_FIELD piece_x, 4 #SET_FIELD piece_o, 0 - #PRINTNL + jsr io.putnl pha jsr print_board pla lda #piece_o jsr computer_perfect_ply pha - #PRINTNL + jsr io.putnl jsr print_board pla ;; Check for correct ply #GET_FIELD main_board,2 #CHECK_ERROR piece_o - jsr getc + jsr io.getc rts .bend @@ -486,16 +486,16 @@ test_perfect_vs_random_computer_player: .block game_loop: ;; Set player X - #STORE_WORD computer_perfect_init, player_x_init_ptr - #STORE_WORD computer_perfect_ply, player_x_ply_ptr + #mem.STORE_WORD computer_perfect_init, player_x_init_ptr + #mem.STORE_WORD computer_perfect_ply, player_x_ply_ptr ;; Set player O - #STORE_WORD computer_random_init, player_o_init_ptr - #STORE_WORD computer_random_ply, player_o_ply_ptr + #mem.STORE_WORD computer_random_init, player_o_init_ptr + #mem.STORE_WORD computer_random_ply, player_o_ply_ptr jsr play_game jsr get_game_state cmp #piece_o ; Random player bne game_loop ; Should never win - #PRINTSNL 'Error' + #io.PRINTSNL 'Error' error: jmp error .bend @@ -503,16 +503,16 @@ test_random_vs_perfect_computer_player: .block game_loop: ;; Set player X - #STORE_WORD computer_random_init, player_x_init_ptr - #STORE_WORD computer_random_ply, player_x_ply_ptr + #mem.STORE_WORD computer_random_init, player_x_init_ptr + #mem.STORE_WORD computer_random_ply, player_x_ply_ptr ;; Set player O - #STORE_WORD computer_perfect_init, player_o_init_ptr - #STORE_WORD computer_perfect_ply, player_o_ply_ptr + #mem.STORE_WORD computer_perfect_init, player_o_init_ptr + #mem.STORE_WORD computer_perfect_ply, player_o_ply_ptr jsr play_game jsr get_game_state cmp #piece_x ; Random player bne game_loop ; Should never win - #PRINTSNL 'Error' + #io.PRINTSNL 'Error' error: jmp error .bend @@ -520,16 +520,16 @@ test_perfect_vs_perfect_computer_player: .block game_loop: ;; Set player X - #STORE_WORD computer_perfect_init, player_x_init_ptr - #STORE_WORD computer_perfect_ply, player_x_ply_ptr + #mem.STORE_WORD computer_perfect_init, player_x_init_ptr + #mem.STORE_WORD computer_perfect_ply, player_x_ply_ptr ;; Set player O - #STORE_WORD computer_perfect_init, player_o_init_ptr - #STORE_WORD computer_perfect_ply, player_o_ply_ptr + #mem.STORE_WORD computer_perfect_init, player_o_init_ptr + #mem.STORE_WORD computer_perfect_ply, player_o_ply_ptr jsr play_game jsr get_game_state cmp #piece_none ; All games should end in beq game_loop ; a draw. - #PRINTSNL 'Error' + #io.PRINTSNL 'Error' error: jmp error .bend @@ -541,13 +541,13 @@ print_random_ply: phx clc adc #'0' - jsr putc - #PRINTS ' plays ' + jsr io.putc + #io.PRINTS ' plays ' pla pha adc #'0' - jsr putc - #PRINTNL + jsr io.putc + jsr io.putnl plx pla rts @@ -561,21 +561,21 @@ print_ply: phx clc adc #'0' - jsr putc - #PRINTS ' plays ' + jsr io.putc + #io.PRINTS ' plays ' pla pha adc #'0' - jsr putc + jsr io.putc lda #'/' - jsr putc + jsr io.putc plx pla pha phx adc #'0' - jsr putc - #PRINTNL + jsr io.putc + jsr io.putnl plx ply pla diff --git a/sw/ttt/human_player.asm b/sw/ttt/human_player.asm @@ -12,17 +12,17 @@ human_player_ply: pha jsr print_board ;; Print question for move - #PRINTS "Player " + #io.PRINTS "Player " pla pha clc adc #'0' - jsr putc - #PRINTS ": " + jsr io.putc + #io.PRINTS ": " ;; Get move and check ;; if move is valid. - jsr getc - jsr putc + jsr io.getc + jsr io.putc ;; Check if user input ;; is in range [1..9] cmp #"1" @@ -38,16 +38,16 @@ human_player_ply: jsr get_field cmp #piece_none bne invalid - #PRINTNL - #PRINTNL + jsr io.putnl + jsr io.putnl ;; Set the piece ldx tmp ; Field number pla ; Piece jsr set_field rts invalid: - #PRINTNL - #PRINTSNL "Not a valid move." + jsr io.putnl + #io.PRINTSNL "Not a valid move." pla jmp human_player_ply .bend diff --git a/sw/ttt/ttt.asm b/sw/ttt/ttt.asm @@ -1,30 +1,9 @@ ;;; If we are included in boot.asm, we ;;; should not set the start address -.weak - BOOT_EMBEDDED = false -.endweak -.if BOOT_EMBEDDED - init_acia = export.init_acia - lfsr_init = export.lfsr_init - lfsr_step = export.lfsr_step - lfsr_state = export.lfsr_state - getc = export.getc - getc_seed_rng = export.getc_seed_rng - putc = export.putc -.else - .if SYMON - .include "boot_symon.l" - start_address = $0300 - .else - .include "boot.l" - start_address = $0200 - .endif + .include "boot.inc" - * = rom_zero_page_end - .dsection zero_page - * = start_address -.endif -.dsection ttt_game + + .dsection ttt_game .section zero_page ;; This temporary variable is used all over the place @@ -67,14 +46,14 @@ board_ascii: .byte ?, ?, ?, ?, ?, ?, ?, ?, ? start_ttt: .block cld - jsr init_acia - jsr lfsr_init + jsr io.init_acia + jsr lfsr.init .if RUN_TESTS jsr run_tests .endif game_loop: - #PRINTSNL '** Tic-Tac-Toe **' - #PRINTNL + #io.PRINTSNL '** Tic-Tac-Toe **' + jsr io.putnl lda #piece_x jsr choose_player lda #piece_o @@ -87,17 +66,17 @@ game_loop: choose_player: .block pha - #PRINTS "Choose player " + #io.PRINTS "Choose player " pla pha clc adc #'0' - jsr putc - #PRINTSNL ':' - #PRINTSNL '1 - Human' - #PRINTSNL '2 - Computer (perfect)' - #PRINTSNL '3 - Computer (random)' - jsr getc_seed_rng + jsr io.putc + #io.PRINTSNL ':' + #io.PRINTSNL '1 - Human' + #io.PRINTSNL '2 - Computer (perfect)' + #io.PRINTSNL '3 - Computer (random)' + jsr io.getc_seed_rng cmp #'1' beq set_human_player cmp #'2' @@ -111,16 +90,16 @@ choose_player: ;; board_ptr to store a temporary ;; variable. set_human_player: - #STORE_WORD human_player_init, tmp - #STORE_WORD human_player_ply, board_ptr + #mem.STORE_WORD human_player_init, tmp + #mem.STORE_WORD human_player_ply, board_ptr jmp set_player set_computer_perfect_player: - #STORE_WORD computer_perfect_init, tmp - #STORE_WORD computer_perfect_ply, board_ptr + #mem.STORE_WORD computer_perfect_init, tmp + #mem.STORE_WORD computer_perfect_ply, board_ptr jmp set_player set_computer_random_player: - #STORE_WORD computer_random_init, tmp - #STORE_WORD computer_random_ply, board_ptr + #mem.STORE_WORD computer_random_init, tmp + #mem.STORE_WORD computer_random_ply, board_ptr set_player: pla cmp #piece_x @@ -158,12 +137,12 @@ set_second_player: .include "computer_player_test.asm" run_tests: ;; jsr game_board_test - ;; #PRINTNL + ;; jsr io.putnl ;; jsr getc ;; jsr mirror_board_test jsr computer_player_test - #PRINTNL - jsr getc + jsr io.putnl + jsr io.getc jmp run_tests .endif diff --git a/sw/via_test/via_test.asm b/sw/via_test/via_test.asm @@ -1,44 +1,36 @@ ;;; Connect LEDs to the 65C22 and enjoy some blinkenlights -.if SYMON - .include "boot_symon.l" -.else - .include "boot.l" -.endif .include "boot.inc" - * = $200 .dsection code - .cerror * > $8000, "RAM exhausted" - .section code init: .block cld - jsr init_acia - jsr getc - PRINTSNL "VIA Test" + jsr io.init_acia + jsr io.getc + #io.PRINTSNL "VIA Test" ;; Configure all ports of A as input lda #$00 - sta via_ddra + sta io.via_ddra ;; Configure all ports of B as output lda #$ff - sta via_ddrb + sta io.via_ddrb loop: jsr read_and_write_via jmp loop .bend read_and_write_via: .block - inc via_orb - PRINTS "IRA: " - lda via_ira - jsr puth + inc io.via_orb + #io.PRINTS "IRA: " + lda io.via_ira + jsr io.puth lda #" " - jsr putc - PRINTS "IRB: " - lda via_irb - jsr puth - PRINTNL + jsr io.putc + #io.PRINTS "IRB: " + lda io.via_irb + jsr io.puth + jsr io.putnl ldx #$00 ldy #$00 delay: diff --git a/tools/boot.py b/tools/boot.py @@ -11,7 +11,7 @@ import os SERIAL_PORT = '/dev/ttyUSB0' SERIAL_SPEED = 19200 -# File upload does not work if GATE is run 100 kHz clock frequency +# File upload does not work if Eris 2010 is run 100 kHz clock frequency # unless SLOW_CPU is set. SLOW_CPU = False # SLOW_CPU = True diff --git a/tools/gfs.py b/tools/gfs.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Access GATE2010 filesystem""" +"""Access Eris 2010 filesystem""" import os import argparse @@ -66,7 +66,7 @@ class GFS: if number_of_blocks > 0: end = b[1:].find(b'\x00') filename = b[1:end+1] - print("{filenumber}: {filename} (0x{blocks:X} blocks)". + print("{filenumber}: {filename} ({blocks} blocks)". format(filenumber=a, filename=filename.decode('utf-8'), blocks=number_of_blocks))