First commit with working cartridge

This commit is contained in:
Piotr Jaczewski 2020-03-23 00:15:15 +01:00
commit 4bd8e8e6b5
6 changed files with 565 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.bin
*.label

27
a1monitor2bin.py Normal file
View File

@ -0,0 +1,27 @@
import codecs
import sys
if __name__ == "__main__":
byte_data = list()
if len(sys.argv) != 2:
print('Usage: python a1monitor2bin.py <file>')
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)

28
bin2a1monitor.py Normal file
View File

@ -0,0 +1,28 @@
import sys
import binascii
if __name__ == "__main__":
if len(sys.argv) != 3:
print('Usage: python bin2a1monitor.py <hex_offset> <file>')
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)

3
build.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
xa -W -C -v -O ASCII -c src/cartridge.xa -l cartridge.label -o cartridge.bin

482
src/cartridge.xa Normal file
View File

@ -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
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
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
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
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"

23
src/rom_content.xa Normal file
View File

@ -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"