From 4bd8e8e6b530be72536b72afbf25a50136e70be7 Mon Sep 17 00:00:00 2001 From: Piotr Jaczewski Date: Mon, 23 Mar 2020 00:15:15 +0100 Subject: [PATCH] First commit with working cartridge --- .gitignore | 2 + a1monitor2bin.py | 27 +++ bin2a1monitor.py | 28 +++ build.sh | 3 + src/cartridge.xa | 482 +++++++++++++++++++++++++++++++++++++++++++++ src/rom_content.xa | 23 +++ 6 files changed, 565 insertions(+) create mode 100644 .gitignore create mode 100644 a1monitor2bin.py create mode 100644 bin2a1monitor.py create mode 100755 build.sh create mode 100644 src/cartridge.xa create mode 100644 src/rom_content.xa diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ad7a9d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.bin +*.label diff --git a/a1monitor2bin.py b/a1monitor2bin.py new file mode 100644 index 0000000..293a447 --- /dev/null +++ b/a1monitor2bin.py @@ -0,0 +1,27 @@ +import codecs +import sys + +if __name__ == "__main__": + + byte_data = list() + + if len(sys.argv) != 2: + print('Usage: python a1monitor2bin.py ') + exit(1) + + with open(sys.argv[1], 'r') as file: + line = file.readline() + while line: + + bytes_arr = line.strip().split(':') + if len(bytes_arr) == 2: + bytes_str_arr = bytes_arr[1].strip().split() + for x in bytes_str_arr: + byte_data.append(codecs.decode(x, 'hex')) + line = file.readline() + + for x in byte_data: + sys.stdout.write(x) + +# to visually compare +# paste apple30th.txt <(hexdump -e '"%08.8_Ax\n"' -e '"%08.8_ax " 8/1 " %02x"' -e '"\n"' apple30th.bin) diff --git a/bin2a1monitor.py b/bin2a1monitor.py new file mode 100644 index 0000000..ad2fd41 --- /dev/null +++ b/bin2a1monitor.py @@ -0,0 +1,28 @@ +import sys +import binascii + +if __name__ == "__main__": + + if len(sys.argv) != 3: + print('Usage: python bin2a1monitor.py ') + exit(1) + + def print_row(offset, row_data): + print(hex(offset)[2:].upper() + ': ' + " ".join(row_data)) + + row_offset = int(sys.argv[1], 0) + row = list() + with open(sys.argv[2], 'rb') as file: + byte = file.read(1) + while byte: + + row.append(binascii.hexlify(byte).upper()) + if len(row) == 8: + print_row(row_offset, row) + row = list() + row_offset += 0x08 + + byte = file.read(1) + + if row: + print_row(row_offset, row) diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..d9918b1 --- /dev/null +++ b/build.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +xa -W -C -v -O ASCII -c src/cartridge.xa -l cartridge.label -o cartridge.bin diff --git a/src/cartridge.xa b/src/cartridge.xa new file mode 100644 index 0000000..7527b4d --- /dev/null +++ b/src/cartridge.xa @@ -0,0 +1,482 @@ +; apple-1 constants +#define monitor $FF1F +#define echo $FFEF +#define prhex $FFE5 +#define kbd_data $D010 +#define kbd_cr $D011 + +; zero page variables + +; content copy variables +#define dest_addr $30 +#define src_addr $32 +#define src_len $34 +#define copy_counter $36 + +; string printing variables +#define str_len $38 +#define str_addr $40 + +; entries scanning variables +#define entries_counter $42 +#define entries_scan_addr $43 +#define entry_segments $45 +#define entry_to_load $46 + +; jmp addr variable +#define jmp_addr $47 + +; option select variables +#define option_data $49 +#define key_data $50 + +* = $4000 + +start + + lda #$0D + jsr echo + jsr print_entries + jsr get_option + + ; option validation + lda option_data + beq start + + cmp rom_content + beq valid_option + bpl start + +valid_option + lda option_data + sta entry_to_load + +;;; load-start +load_entry + + ; init entries counter + lda #$01 + sta entries_counter + + ; init entries scan addr + lda #rom_content + sta entries_scan_addr+1 + + ; skip number of entries byte + ldx #entries_scan_addr + jsr increment_16bit + +check_load + + ; load number of entry segments + ldy #$00 + lda (entries_scan_addr),Y + sta entry_segments + + ; skip number of entry segments + ldx #entries_scan_addr + jsr increment_16bit + + lda entry_to_load + cmp entries_counter + + bne skip_entry + +load_segment + + ; load segment length + ldy #$00 + lda (entries_scan_addr),Y + sta src_len + ldx #entries_scan_addr + jsr increment_16bit + lda (entries_scan_addr),Y + sta src_len+1 + + ; load dest addr + ldx #entries_scan_addr + jsr increment_16bit + lda (entries_scan_addr),Y + sta dest_addr + ldx #entries_scan_addr + jsr increment_16bit + lda (entries_scan_addr),Y + sta dest_addr+1 + + ; load source addr + ldx #entries_scan_addr + jsr increment_16bit + lda (entries_scan_addr),Y + sta src_addr + ldx #entries_scan_addr + jsr increment_16bit + lda (entries_scan_addr),Y + sta src_addr+1 + + ; copy segment from source to destination + jsr init_copy + + ; proceed to next segment + ldx #entries_scan_addr + jsr increment_16bit + + dec entry_segments + bne load_segment + +load_program + + ; skip entry string + ldy #$00 + lda (entries_scan_addr),Y + tay + iny + tya + ldx #entries_scan_addr + jsr add_to_addr + + ; load entry jump address + lda entries_scan_addr + sta dest_addr + lda entries_scan_addr+1 + sta dest_addr+1 + + ldy #$00 + lda (dest_addr),Y + sta jmp_addr + + iny + + lda (dest_addr),Y + sta jmp_addr+1 + + jmp (jmp_addr) + +skip_entry + ; skip length, dest addr, content + ldx #entries_scan_addr + lda #$06 + jsr add_to_addr + dec entry_segments + bne skip_entry + + ; skip entry string + ldy #$00 + lda (entries_scan_addr),Y + tay + iny + tya + ldx #entries_scan_addr + jsr add_to_addr + + ; skip entry jump address + lda #$02 + ldx #entries_scan_addr + jsr add_to_addr + + inc entries_counter + jmp check_load + +init_copy + lda #$00 + sta copy_counter + sta copy_counter+1 +copy + ; load byte from rom into ram + ldy #$00 + lda (src_addr),Y + sta (dest_addr),Y + + ; increment source address + ldx #src_addr + jsr increment_16bit + + ; increment destination address + ldx #dest_addr + jsr increment_16bit + + ; compare counter lower byte with source length lower byte + ; if not equal increment counter + lda src_len + cmp copy_counter + bne increment_copy_counter + + ; compare counter upper byte with content length upper byte + ; if not equal increment counter + lda src_len+1 + cmp copy_counter+1 + bne increment_copy_counter + + rts + +increment_copy_counter + ldx #copy_counter + jsr increment_16bit + + jmp copy + +;;; load-end + +;;; printing +print_entries + ; print welcome string + lda #welcome_str + sta str_addr+1 + jsr print_str + + ; init entries counter + lda #$00 + sta entries_counter + + ; init entries scan addr + lda #rom_content + sta entries_scan_addr+1 + + ; skip number of entries byte + ldx #entries_scan_addr + jsr increment_16bit + +print_entry + + ; load number of entry segments + ldy #$00 + lda (entries_scan_addr),Y + sta entry_segments + + ; skip number of entry segments + ldx #entries_scan_addr + jsr increment_16bit + +skip_segment + ; skip length, dest addr, content + ldx #entries_scan_addr + lda #$06 + jsr add_to_addr + dec entry_segments + bne skip_segment + + ; print entry number + inc entries_counter + ldx #entries_counter + jsr print_number + + ; print dot and space + lda #'.' + jsr echo + lda #' ' + jsr echo + + ; print entry string + lda entries_scan_addr + sta str_addr + lda entries_scan_addr+1 + sta str_addr+1 + jsr print_str + lda #$0D + jsr echo + + ; skip entry string + ldy #$00 + lda (entries_scan_addr),Y + tay + iny + tya + ldx #entries_scan_addr + jsr add_to_addr + + ; skip entry jump address + lda #$02 + jsr add_to_addr + + ; if not last entry then repeat + lda rom_content + cmp entries_counter + bne print_entry + +print_entries_done + ; print choose string + lda #choose_str + sta str_addr+1 + jsr print_str + + rts + +print_str + ; store string length + ldy #$00 + lda (str_addr),Y + sta str_len + + ; skip length byte from string address + ldx #str_addr + jsr increment_16bit + +print_str_loop + lda (str_addr),Y + jsr echo + iny + cpy str_len + bne print_str_loop + rts + +; prints only numbers in range 0-19 +print_number + lda #$09 + cmp $00,X + bmi greater_than_nine + lda $00,X + jsr prhex + jmp print_number_done +greater_than_nine + lda #$01 + jsr prhex + ; save number in Y + lda $00,X + tay + ; decrement 10 + lda #$09 + sta $00,X + tya + sbc $00,X + jsr prhex + ; restore number from Y + tya + sta $00,X +print_number_done + rts + +;;; printing-end + +;;; get-option +get_option + ; init digits counter + ldx #$00 +get_key + ; wait for key + lda kbd_cr + bpl get_key + lda kbd_data + + ; store key data + sta key_data + + ; if CR check if option is satisfied + cmp #$8D ; CR + beq get_key_done + + ; check range 0-9 + cmp #$B0 ; 0 + bmi get_key + + cmp #$BA ; 9 + bpl get_key + + ; which digit we are processing? + txa + + ; second digit + cmp #$01 + beq two_digit + + ; if we have already processed second digit then only CR is eligible + cmp #$02 + beq get_key + +one_digit + ; ??? + sec + lda key_data + sbc #$B0 + sta option_data + +echo_key + ; echo digit + lda key_data + jsr echo + + ; increment digit counter + inx + jmp get_key + +two_digit + lda #$00 + ldy option_data + ; if first digit was 0 then simply add second to A + beq two_digit_inc_done + clc +two_digit_inc + ; loop adding 10 to A first digit times + adc #$0A + dey + bne two_digit_inc +two_digit_inc_done + ; save current option calculation on stack + pha + + ; compute int value from second digit + sec + lda key_data + sbc #$B0 + ; and store in option_data + sta option_data + + ; restore previously calculated first digit part from stack + pla + clc + ; and add second digit value + adc option_data + ; store fully computed option value + sta option_data + ; and wait for CR + jmp echo_key + +get_key_done + ; if CR was pressed as the first key, then simply omit + txa + beq get_key + + ; print CR + lda #$8D ; CR + jsr echo + rts + +;;; get-option-end + +;;; tools +increment_16bit + inc $00,X + bne increment_16bit_done + inx + inc $00,X +increment_16bit_done + rts + +add_to_addr + clc + adc $00,X + sta $00,X + bcs add_to_addr_done + jmp add_to_addr_done +add_to_addr_carry + inx + inc $00,X +add_to_addr_done + rts + +;;; tools-end + + +welcome_str .byt $14,"AVAILABLE OPTIONS:",$0D,$0D +choose_str .byt $0F,$0D,"CHOOSE OPTION:" + +rom_content +#include "src/rom_content.xa" diff --git a/src/rom_content.xa b/src/rom_content.xa new file mode 100644 index 0000000..b975cb8 --- /dev/null +++ b/src/rom_content.xa @@ -0,0 +1,23 @@ +number_of_entries .byt $02 + +basic +basic_seg .byt $01 +basic_1_len .word $1000 +basic_1_addr .word $e000 +basic_1_cont_start .word basic_cont +basic_str .byt $05,"BASIC" +basic_jmp_addr .word $e000 + +apple30th +apple30th_seg .byt $02 +apple30th_1_len .word $0D80 +apple30th_1_addr .word $0280 +apple30th_1_cont_start .word apple30th_cont +apple30th_2_len .word $0D80 +apple30th_2_addr .word $0280 +apple30th_2_cont_start .word apple30th_cont +apple30th_str .byt $13,"APPLE 30TH BIRTHDAY" +apple30th_jmp_addr .word $0280 + +basic_cont .bin 0,4096,"inc/basic.bin" +apple30th_cont .bin 0,3456,"inc/apple30th.bin"