-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy path47loader_dynamic.asm
134 lines (120 loc) · 5.25 KB
/
47loader_dynamic.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
;; 47loader (c) Stephen Williams 2013-2015
;; See LICENSE for distribution terms
;; "Dynamic" loader. Loads a table of addresses and data
;; lengths, then loads the blocks at the specified addresses.
;;
;; The table consists of the 16-bit address in big-endian
;; format, followed by the 16-bit data length in big-endian
;; format. Only bits 0-14 of the length entry define the
;; length; bit 15 is a flag indicating whether to change the
;; load direction before loading the block.
;;
;; On initial entry to loader_dynamic, forward loading is
;; assumed.
;;
;; Define the following:
;;
;; LOADER_DYNAMIC_TABLE_ADDR:
;; the address at which to load the table.
;;
;; LOADER_DYNAMIC_INITIAL:
;; if defined, this is the address of a routine to call to fetch
;; the length of the table. If not defined, loader_entry is used.
;;
;; LOADER_DYNAMIC_FORWARDS_ONLY:
;; if defined, direction changes are disabled; define this to
;; save a few bytes if all the dynamic loads are forwards.
;;
;; LOADER_DYNAMIC_ONE_BYTE_LENGTHS:
;; if defined, the table uses only a single byte to store each
;; length and direction change flag. All dynamic blocks are
;; thus no larger than 127 bytes.
;;
;; LOADER_DYNAMIC_FIXED_LENGTH:
;; if defined, the table contains no lengths or direction
;; changes at all. Each dynamic block has the length specified
;; by this define. So if every block is 32 bytes long, define
;; LOADER_DYNAMIC_FIXED_LENGTH EQU 32.
loader_dynamic:
;; bootstrap the progressive load by reading two
;; bytes: the length of the table
ld ix,LOADER_DYNAMIC_TABLE_ADDR
ld de,2
ifdef LOADER_DYNAMIC_INITIAL
;; if defined, call this routine to load the first block
call LOADER_DYNAMIC_INITIAL
else
call loader_entry
endif
ifndef LOADER_DIE_ON_ERROR
ret nc
endif
;; that loaded two bytes, the length of the table, which
;; will be the next block to load
ld de,(LOADER_DYNAMIC_TABLE_ADDR) ; get table length
;; load the table
ld ix,LOADER_DYNAMIC_TABLE_ADDR
call loader_resume
ifndef LOADER_DIE_ON_ERROR
ret nc
endif
;; disable the border once the screen starts loading
ifdef LOADER_TOGGLE_BORDER
call loader_disable_border
endif
;; enter the main loop with the table address in HL
ld hl,LOADER_DYNAMIC_TABLE_ADDR
.loader_dynamic_loop:
;; HL is pointing at the next table entry
ld a,(hl) ; look at the byte
and a ; see if it's zero
scf ; signal successful load
ret z ; if A is zero, we're done
;; if still here, A is not zero, and HL is
;; pointing at the address to load in big-endian
;; format
ld ixh,a ; high byte of address into IX
inc hl ; advance table pointer
ld a,(hl) ; low byte of address into accumulator
ld ixl,a ; and into IX
inc hl ; advance pointer
ifndef LOADER_DYNAMIC_FIXED_LENGTH
;; next, we read the length of the data to load, again
;; in big-endian format
ifndef LOADER_DYNAMIC_ONE_BYTE_LENGTHS
ld d,(hl) ; high byte of length into DE
inc hl ; advance table pointer
endif
ld e,(hl) ; low byte of length into DE
inc hl ; advance table pointer
push hl ; stack the table pointer
ifndef LOADER_DYNAMIC_FORWARDS_ONLY
;; if bit 15 of the length is set (or bit 7 for one-byte
;; lengths), we need to change direction
ifndef LOADER_DYNAMIC_ONE_BYTE_LENGTHS
bit 7,d ; test the flag bit
res 7,d ; clear the flag bit
else
bit 7,e ; test the flag bit
res 7,e ; clear the flag bit
endif
call nz,loader_change_direction ; change direction if flag set
endif
else ; LOADER_DYNAMIC_FIXED_LENGTH is defined
;; in this case, all dynamic chunks are the same length
;; and can be hard-coded. At this point, DE is 0
if LOADER_DYNAMIC_FIXED_LENGTH < 256
ld e,LOADER_DYNAMIC_FIXED_LENGTH ;single-byte length into DE
else
ld de,LOADER_DYNAMIC_FIXED_LENGTH ;two-byte length into DE
endif
push hl ; stack the table pointer
endif ; LOADER_DYNAMIC_FIXED_LENGTH
;; with IX and DE set up, we can load the block
call loader_resume ; load the block
pop hl ; restore the table pointer
jr c,.loader_dynamic_loop ; loop if load was successful
;; if still here, the load failed
ifndef LOADER_DIE_ON_ERROR
ret
endif