CMD16
334 | STA CMDHI
335 | JSR SDCMD
336 | JSR GETR1
337 | CMP #0
338 | BNE @IOERROR ; error!
339 |
340 | @END: LDA SS,X
341 | ORA #CARD_INIT ; initialized
342 | STA SS,X
343 | LDA CTRL,X
344 | ORA #ECE ; enable 7MHz
345 | STA CTRL,X
346 | CLC ; all ok
347 | LDY #NO_ERR
348 | BCC @END1
349 |
350 | @IOERROR: SEC
351 | LDY #ERR_IOERR ; init error
352 | @END1: LDA SS,X ; set CS high
353 | ORA #SS0
354 | STA SS,X
355 | TYA ; retval in A
356 | KNOWNRTS: RTS
357 |
358 |
359 | TEXT: .asciiz " Apple][Sd v1.2.2 (c)2021 Florian Reitz"
360 | .assert(*-TEXT)=40, error, "TEXT must be 40 bytes long"
361 |
362 |
363 | CMD0: .byt $40, $00, $00
364 | .byt $00, $00, $95
365 | CMD1: .byt $41, $00, $00
366 | .byt $00, $00, $F9
367 | CMD8: .byt $48, $00, $00
368 | .byt $01, $AA, $87
369 | CMD16: .byt $50, $00, $00
370 | .byt $02, $00, $FF
371 | CMD55: .byt $77, $00, $00
372 | .byt $00, $00, $FF
373 | CMD58: .byt $7A, $00, $00
374 | .byt $00, $00, $FF
375 | ACMD4140: .byt $69, $40, $00
376 | .byt $00, $00, $77
377 | ACMD410: .byt $69, $00, $00
378 | .byt $00, $00, $FF
379 |
--------------------------------------------------------------------------------
/Firmware/src/Helper.s:
--------------------------------------------------------------------------------
1 | ;*******************************
2 | ;
3 | ; Apple][Sd Firmware
4 | ; Version 1.2.3
5 | ; Helper functions
6 | ;
7 | ; (c) Florian Reitz, 2017 - 2021
8 | ;
9 | ; X register usually contains SLOT16
10 | ; Y register is used for counting or SLOT
11 | ;
12 | ;*******************************
13 |
14 | .export SDCMD
15 | .export GETR1
16 | .export GETR3
17 | .export GETBLOCK
18 | .export COMMAND
19 | .export CARDDET
20 | .export WRPROT
21 | .export INITED
22 |
23 |
24 | .include "AppleIISd.inc"
25 | .segment "EXTROM"
26 |
27 |
28 | ;*******************************
29 | ;
30 | ; Send SD command
31 | ; Call with command in CMDHI and CMDLO
32 | ;
33 | ;*******************************
34 |
35 | SDCMD: PHY
36 | LDY #0
37 | @LOOP: LDA (CMDLO),Y
38 | STA DATA,X
39 | @WAIT: LDA CTRL,X ; TC is in N
40 | BPL @WAIT
41 | INY
42 | CPY #6
43 | BCC @LOOP
44 | PLY
45 | RTS
46 |
47 |
48 | ;*******************************
49 | ;
50 | ; Get R1
51 | ; R1 is in A
52 | ;
53 | ;*******************************
54 |
55 | GETR1: LDA #DUMMY
56 | STA DATA,X
57 | @WAIT: LDA CTRL,X
58 | BPL @WAIT
59 | LDA DATA,X ; get response
60 | BMI GETR1 ; wait for MSB=0
61 | PHA
62 | LDA #DUMMY
63 | STA DATA,X ; send another dummy
64 | PLA ; restore R1
65 | RTS
66 |
67 | ;*******************************
68 | ;
69 | ; Get R3 or R7
70 | ; R1 is in A
71 | ; R3 is in scratchpad ram
72 | ;
73 | ;*******************************
74 |
75 | GETR3: JSR GETR1 ; get R1 first
76 | PHA ; save R1
77 | PHY ; save Y
78 | LDY #04 ; load counter
79 | JMP @WAIT ; first byte is already there
80 | @LOOP: LDA #DUMMY ; send dummy
81 | STA DATA,X
82 | @WAIT: LDA CTRL,X
83 | BPL @WAIT
84 | LDA DATA,X
85 | PHA
86 | DEY
87 | BNE @LOOP ; do 4 times
88 | LDY SLOT
89 | PLA
90 | STA R33,Y ; save R3
91 | PLA
92 | STA R32,Y
93 | PLA
94 | STA R31,Y
95 | PLA
96 | STA R30,Y ; R30 is MSB
97 | PLY ; restore Y
98 | LDA #DUMMY
99 | STA DATA,X ; send another dummy
100 | PLA ; restore R1
101 | RTS
102 |
103 |
104 | ;*******************************
105 | ;
106 | ; Calculate block address
107 | ; Unit number is in $43 DSSS0000
108 | ; Block no is in $46-47
109 | ; Address is in R30-R33
110 | ;
111 | ;*******************************
112 |
113 | GETBLOCK: PHX ; save X
114 | PHY ; save Y
115 | LDX SLOT ; SLOT is now in X
116 | LDY SLOT16
117 | LDA BLOCKNUM ; store block num
118 | STA R33,X ; in R30-R33
119 | LDA BLOCKNUM+1
120 | STA R32,X
121 | STZ R31,X
122 | STZ R30,X
123 |
124 | TYA ; get SLOT16
125 | EOR DSNUMBER
126 | AND #$70 ; check only slot bits
127 | BEQ @DRIVE ; it is our slot
128 | LDA #2 ; it is a phantom slot
129 | STA R31,X
130 |
131 | @DRIVE: LDA DSNUMBER ; drive number
132 | BPL @SDHC ; D1
133 | LDA R31,X ; D2
134 | INC A
135 | STA R31,X
136 |
137 | @SDHC: LDA #SDHC
138 | AND SS,Y ; if card is SDHC,
139 | BNE @END ; use block addressing
140 |
141 | LDY #9 ; ASL can't be used with Y
142 | @LOOP: ASL R33,X ; mul block num
143 | ROL R32,X ; by 512 to get
144 | ROL R31,X ; real address
145 | ROL R30,X
146 | DEY
147 | BNE @LOOP
148 |
149 | @END: PLY ; restore Y
150 | PLX ; restore X
151 | RTS
152 |
153 |
154 | ;*******************************
155 | ;
156 | ; Send SD command
157 | ; Cmd is in A
158 | ;
159 | ;*******************************
160 |
161 | COMMAND: PHY ; save Y
162 | LDY SLOT
163 | STA DATA,X ; send command
164 | LDA R30,Y ; get arg from R30 on
165 | STA DATA,X
166 | LDA R31,Y
167 | STA DATA,X
168 | LDA R32,Y
169 | STA DATA,X
170 | LDA R33,Y
171 | STA DATA,X
172 | LDA #DUMMY
173 | STA DATA,X ; dummy crc
174 | JSR GETR1
175 | PLY ; restore Y
176 | RTS
177 |
178 |
179 | ;*******************************
180 | ;
181 | ; Check for card detect
182 | ; X must contain SLOT16
183 | ;
184 | ; C Clear - card in slot
185 | ; Set - no card in slot
186 | ;
187 | ;*******************************
188 |
189 | CARDDET: PHA
190 | LDA #CD ; 0: card in
191 | BIT SS,X ; 1: card out
192 | CLC
193 | BEQ @DONE ; card is in
194 | SEC ; card is out
195 | @DONE: PLA
196 | RTS
197 |
198 |
199 | ;*******************************
200 | ;
201 | ; Check for write protect
202 | ; X must contain SLOT16
203 | ;
204 | ; C Clear - card not protected
205 | ; Set - card write protected
206 | ;
207 | ;*******************************
208 |
209 | WRPROT: PHA
210 | LDA #WP ; 0: write enabled
211 | BIT SS,X ; 1: write disabled
212 | CLC
213 | BEQ @DONE
214 | SEC
215 | @DONE: PLA
216 | RTS
217 |
218 |
219 | ;*******************************
220 | ;
221 | ; Check if card is initialized
222 | ; X must contain SLOT16
223 | ;
224 | ; C Clear - card initialized
225 | ; Set - card not initialized
226 | ;
227 | ;*******************************
228 |
229 | INITED: PHA
230 | LDA #CARD_INIT ; 0: card not initialized
231 | BIT SS,X ; 1: card initialized
232 | CLC
233 | BNE @DONE
234 | SEC
235 | @DONE: PLA
236 | RTS
237 |
--------------------------------------------------------------------------------
/Firmware/src/ProDOS.s:
--------------------------------------------------------------------------------
1 | ;*******************************
2 | ;
3 | ; Apple][Sd Firmware
4 | ; Version 1.2.3
5 | ; ProDOS functions
6 | ;
7 | ; (c) Florian Reitz, 2017 - 2021
8 | ;
9 | ; X register usually contains SLOT16
10 | ; Y register is used for counting or SLOT
11 | ;
12 | ;*******************************
13 |
14 | .export PRODOS
15 | .export STATUS
16 | .export READ
17 | .export WRITE
18 |
19 | .import COMMAND
20 | .import SDCMD
21 | .import GETBLOCK
22 | .import CARDDET
23 | .import INITED
24 | .import INIT
25 | .import WRPROT
26 | .import GETR1
27 | .import GETR3
28 |
29 | .include "AppleIISd.inc"
30 | .segment "EXTROM"
31 |
32 |
33 | ;*******************************
34 | ;
35 | ; ProDOS command dispatcher
36 | ;
37 | ; $42-$47 MLI input locations
38 | ; X Slot*16
39 | ; Y Slot
40 | ;
41 | ; C Clear - No error
42 | ; Set - Error
43 | ; A $00 - No error
44 | ; $01 - Unknown command
45 | ;
46 | ;*******************************
47 |
48 | PRODOS: LDA DCMD ; get command
49 | BEQ @STATUS ; branch if cmd is 0
50 | CMP #1
51 | BEQ @READ
52 | CMP #2
53 | BEQ @WRITE
54 | LDA #ERR_BADCMD ; unknown command
55 | SEC
56 | RTS
57 |
58 | @STATUS: JMP STATUS
59 | @READ: JMP READ
60 | @WRITE: JMP WRITE
61 |
62 |
63 | ;*******************************
64 | ;
65 | ; Status request
66 | ; $43 Unit number DSSS000
67 | ; $44-45 Unused
68 | ; $46-47 Unused
69 | ;
70 | ; C Clear - No error
71 | ; Set - Error
72 | ; A $00 - No error
73 | ; $28 - No card inserted
74 | ; $2B - Card write protected
75 | ; X - Blocks avail (low byte)
76 | ; Y - Blocks avail (high byte)
77 | ;
78 | ;*******************************
79 |
80 | STATUS: LDA #NO_ERR ; Thanks for this one, Antoine!
81 | JSR CARDDET
82 | BCC @WRPROT
83 | LDA #ERR_NODRIVE; no card inserted
84 | BNE @DONE
85 |
86 | @WRPROT: JSR WRPROT
87 | BCC @DONE
88 | LDA #ERR_NOWRITE; card write protected
89 |
90 | @DONE: LDX #$FF ; 32 MB partition
91 | LDY #$FF
92 | RTS
93 |
94 |
95 | ;*******************************
96 | ;
97 | ; Read 512 byte block
98 | ; $43 Unit number DSSS0000
99 | ; $44-45 Address (LO/HI) of buffer
100 | ; $46-47 Block number (LO/HI)
101 | ;
102 | ; C Clear - No error
103 | ; Set - Error
104 | ; A $00 - No error
105 | ; $27 - Bad block number
106 | ; $28 - No card inserted
107 | ;
108 | ;*******************************
109 |
110 | READ: JSR CARDDET ; check for card
111 | BCS @NDERROR ; no card
112 |
113 | JSR INITED ; check for initialization
114 | BCC @GETBLOCK
115 |
116 | JSR INIT ; initialize card
117 | BCS @NDERROR ; init failed
118 |
119 | @GETBLOCK: JSR GETBLOCK ; calc block address
120 |
121 | LDA SS,X ; enable /CS
122 | AND #<~SS0
123 | STA SS,X
124 | LDA #$51 ; send CMD17
125 | JSR COMMAND ; send command
126 | CMP #0
127 | BNE @IOERROR ; check for error
128 |
129 | @GETTOK: LDA #DUMMY ; get data token
130 | STA DATA,X
131 | LDA DATA,X ; get response
132 | CMP #$FE
133 | BNE @GETTOK ; wait for $FE
134 |
135 | LDA CTRL,X ; enable FRX
136 | ORA #FRX
137 | STA CTRL,X
138 | LDA #DUMMY
139 | STA DATA,X
140 |
141 | LDY #0
142 | @LOOP1: LDA DATA,X ; read data from card
143 | STA (BUFFER),Y
144 | INY
145 | BNE @LOOP1
146 | INC BUFFER+1 ; inc msb on page boundary
147 | @LOOP2: LDA DATA,X
148 | STA (BUFFER),Y
149 | INY
150 | BNE @LOOP2
151 | DEC BUFFER+1
152 |
153 | @CRC: LDA DATA,X ; read two bytes crc
154 | LDA DATA,X ; and ignore
155 | LDA DATA,X ; read a dummy byte
156 |
157 | LDA CTRL,X ; disable FRX
158 | AND #<~FRX
159 | STA CTRL,X
160 | CLC ; no error
161 | LDA #NO_ERR
162 |
163 | @DONE: PHP
164 | PHA
165 | LDA SS,X
166 | ORA #SS0
167 | STA SS,X ; disable /CS
168 | PLA
169 | PLP
170 | RTS
171 |
172 | @IOERROR: SEC ; an error occured
173 | LDA #ERR_IOERR
174 | BRA @DONE
175 |
176 | @NDERROR: SEC ; an error occured
177 | LDA #ERR_NODRIVE
178 | BRA @DONE
179 |
180 |
181 | ;*******************************
182 | ;
183 | ; Write 512 byte block
184 | ; $43 Unit number DSSS0000
185 | ; $44-45 Address (LO/HI) of buffer
186 | ; $46-47 Block number (LO/HI)
187 | ;
188 | ; C Clear - No error
189 | ; Set - Error
190 | ; A $00 - No error
191 | ; $27 - I/O error or bad block number
192 | ; $2B - Card write protected
193 | ;
194 | ;*******************************
195 |
196 | WRITE: JSR WRPROT
197 | BCS @WPERROR ; card write protected
198 |
199 | JSR GETBLOCK ; calc block address
200 |
201 | LDA SS,X ; enable /CS
202 | AND #<~SS0
203 | STA SS,X
204 | LDA #$58 ; send CMD24
205 | JSR COMMAND ; send command
206 | CMP #0
207 | BNE @IOERROR ; check for error
208 |
209 | LDA #DUMMY
210 | STA DATA,X ; send dummy
211 | LDA #$FE
212 | STA DATA,X ; send data token
213 |
214 | LDY #0
215 | @LOOP1: LDA (BUFFER),Y
216 | STA DATA,X
217 | INY
218 | BNE @LOOP1
219 | INC BUFFER+1
220 | @LOOP2: LDA (BUFFER),Y
221 | STA DATA,X
222 | INY
223 | BNE @LOOP2
224 | DEC BUFFER+1
225 |
226 | @CRC: LDA #DUMMY
227 | STA DATA,X ; send 2 dummy crc bytes
228 | STA DATA,X
229 |
230 | STA DATA,X ; get data response
231 | LDA DATA,X
232 | AND #$1F
233 | CMP #$05
234 | BNE @IOERROR ; check for write error
235 | CLC ; no error
236 | LDA #NO_ERR
237 |
238 | @DONE: PHP
239 | PHA
240 | @WAIT: LDA #DUMMY
241 | STA DATA,X ; wait for write cycle
242 | LDA DATA,X ; to complete
243 | BEQ @WAIT
244 |
245 | LDA SS,X ; disable /CS
246 | ORA #SS0
247 | STA SS,X
248 | PLA
249 | PLP
250 | RTS
251 |
252 | @IOERROR: SEC ; an error occured
253 | LDA #ERR_IOERR
254 | BRA @DONE
255 |
256 | @WPERROR: SEC
257 | LDA #ERR_NOWRITE
258 | BRA @DONE
259 |
--------------------------------------------------------------------------------
/Firmware/src/Smartport.s:
--------------------------------------------------------------------------------
1 | ;*******************************
2 | ;
3 | ; Apple][Sd Firmware
4 | ; Version 1.2.3
5 | ; Smartport functions
6 | ;
7 | ; (c) Florian Reitz, 2017 - 2021
8 | ;
9 | ; X register usually contains SLOT16
10 | ; Y register is used for counting or SLOT
11 | ;
12 | ;*******************************
13 |
14 | .export SMARTPORT
15 |
16 | .import READ
17 | .import WRITE
18 | .import CARDDET
19 | .import WRPROT
20 |
21 | .include "AppleIISd.inc"
22 | .segment "EXTROM"
23 |
24 |
25 | ;*******************************
26 | ;
27 | ; Smartport command dispatcher
28 | ;
29 | ; $42-$47 MLI input locations
30 | ; X Slot*16
31 | ; Y Slot
32 | ;
33 | ; C Clear - No error
34 | ; Set - Error
35 | ; A $00 - No error
36 | ; $01 - Unknown command
37 | ;
38 | ;*******************************
39 |
40 | SMARTPORT: LDY #SMZPSIZE-1 ; save zeropage area for Smarport
41 | @SAVEZP: LDA SMZPAREA,Y
42 | PHA
43 | DEY
44 | BPL @SAVEZP
45 |
46 | TSX ; get call address
47 | LDA $103+PDZPSIZE+SMZPSIZE,X
48 | STA SMPARAMLIST ; store temporarily
49 | CLC
50 | ADC #3 ; adjust return address
51 | STA $103+PDZPSIZE+SMZPSIZE,X
52 | LDA $104+PDZPSIZE+SMZPSIZE,X
53 | STA SMPARAMLIST+1
54 | ADC #0
55 | STA $104+PDZPSIZE+SMZPSIZE,X
56 |
57 | LDY #1 ; get command code
58 | LDA (SMPARAMLIST),Y
59 | STA SMCMD
60 | INY
61 | LDA (SMPARAMLIST),Y
62 | TAX
63 | INY
64 | LDA (SMPARAMLIST),Y
65 | STA SMPARAMLIST+1 ; is now parameter list
66 | STX SMPARAMLIST
67 |
68 | LDA #ERR_BADCMD ; suspect bad command
69 | LDX SMCMD
70 | CPX #$09+1 ; command too large
71 | BCS @END
72 |
73 | LDA (SMPARAMLIST) ; parameter count
74 | CMP REQPARAMCOUNT,X
75 | BNE @COUNTMISMATCH
76 |
77 | LDY #1 ; get drive number
78 | LDA (SMPARAMLIST),Y
79 | LDY SLOT
80 | STA DRVNUM,Y
81 |
82 | TXA ; SMCMD
83 | ASL A ; shift for use of word addresses
84 | TAX
85 | JSR @JMPSPCOMMAND ; Y holds SLOT
86 | BCS @END ; jump on error
87 | LDA #NO_ERR
88 |
89 | @END: TAX ; save retval
90 | LDY #0 ; restore zeropage
91 | @RESTZP: PLA
92 | STA SMZPAREA,Y
93 | INY
94 | CPY #SMZPSIZE
95 | BCC @RESTZP
96 |
97 | TXA
98 | ;warum feste anzahl an bytes f�r return wert?
99 | LDY #2 ; highbyte of # bytes transferred
100 | LDX #0 ; low byte of # bytes transferred
101 | ;warum wird mit #1 verglichen?
102 | CMP #1 ; C=1 if A != NO_ERR
103 | RTS
104 |
105 | @COUNTMISMATCH:
106 | LDA #ERR_BADPCNT
107 | BRA @END
108 |
109 | @JMPSPCOMMAND: ; use offset from cmd*2
110 | JMP (SPDISPATCH,X)
111 |
112 |
113 |
114 | ; Smartport Status command
115 | ;
116 | SMSTATUS: JSR GETCSLIST
117 | LDY SLOT
118 | LDA DRVNUM,Y
119 | BNE @PARTITION ; status call for a partition
120 |
121 | LDA SMCSCODE
122 | BEQ @STATUS00 ; status call 0 for the bus
123 | LDA #ERR_BADCTL ; calls other than 0 are not allowed
124 | SEC
125 | RTS
126 |
127 | ; TODO support partitions based on card size
128 | @STATUS00: LDA #4 ; support 4 partitions
129 | STA (SMCMDLIST)
130 |
131 | LDY #7
132 | @LOOP00: LDA STATUS00DATA-1,Y
133 | STA (SMCMDLIST),Y
134 | DEY
135 | BNE @LOOP00
136 | CLC
137 | RTS
138 |
139 | @PARTITION: LDX SMCSCODE
140 | BEQ @STATUS03 ; 0: device status
141 | DEX
142 | BEQ @GETDCB ; 1: get DCB
143 | DEX
144 | DEX
145 | BEQ @STATUS03 ; 3: get DIB
146 | LDA #ERR_BADCTL
147 | SEC
148 | RTS
149 |
150 | @GETDCB: LDA #1 ; return 'empty' DCB, one byte
151 | STA (SMCMDLIST)
152 | TAY
153 | LDA #NO_ERR
154 | STA (SMCMDLIST),Y
155 | CLC
156 | RTS
157 |
158 | @STATUS03: LDA #$E8 ; block device, read, write, format,
159 | ; not online, no write-protect
160 | LDX SLOT16
161 | JSR CARDDET
162 | BCS @WRPROT
163 | ORA #$10 ; card inserted
164 | @WRPROT: JSR WRPROT
165 | BCC @STATUSBYTE
166 | ORA #$04 ; SD card write-protected
167 | @STATUSBYTE:STA (SMCMDLIST)
168 |
169 | LDY #1 ; block count, always $00FFFF
170 | LDA #$FF
171 | STA (SMCMDLIST),Y
172 | INY
173 | STA (SMCMDLIST),Y
174 | INY
175 | LDA #0
176 | STA (SMCMDLIST),Y
177 |
178 | LDA SMCSCODE
179 | BEQ @DONE ; done if code 0, else get DIB, 21 bytes
180 |
181 | LDY #4
182 | @LOOP: LDA STATUS3DATA-4,Y
183 | STA (SMCMDLIST),Y
184 | INY
185 | CPY #21+4
186 | BCC @LOOP
187 |
188 | @DONE: CLC
189 | RTS
190 |
191 |
192 | ; Smartport Control command
193 | ;
194 | ; no controls supported, yet
195 | ;
196 | SMCONTROL: JSR GETCSLIST
197 | LDX SMCSCODE
198 | BEQ @RESET ; 0: Reset
199 | DEX
200 | BEQ @SETDCB ; 1: SetDCB
201 | DEX
202 | BEQ @NEWLINE ; 2: SetNewLine
203 | DEX
204 | BEQ @IRQ ; 3: ServiceInterrupt
205 | DEX
206 | BEQ @EJECT ; 4: Eject
207 |
208 | @NEWLINE: LDA #ERR_BADCTL
209 | SEC
210 | @RESET:
211 | @SETDCB:
212 | @EJECT: LDA #NO_ERR ; only return OK
213 | CLC
214 | RTS
215 |
216 | @IRQ: LDA #ERR_NOINT ; interrupts not supported
217 | SEC
218 | RTS
219 |
220 |
221 | ; Get control/status list pointer and code
222 | ;
223 | GETCSLIST: LDY #2
224 | LDA (SMPARAMLIST),Y
225 | STA SMCMDLIST ; get buffer pointer
226 | INY
227 | LDA (SMPARAMLIST),Y
228 | STA SMCMDLIST+1
229 | INY
230 | LDA (SMPARAMLIST),Y
231 | STA SMCSCODE ; get status/control code
232 | RTS
233 |
234 |
235 | ; Smartport Read Block command
236 | ;
237 | ; reads a 512-byte block using the ProDOS function
238 | ;
239 | SMREADBLOCK:
240 | JSR TRANSLATE
241 | BCC @READ
242 | RTS
243 |
244 | @READ: LDX SLOT16
245 | LDY SLOT
246 | JMP READ ; call ProDOS read
247 |
248 |
249 |
250 | ; Smartport Write Block command
251 | ;
252 | ; writes a 512-byte block using the ProDOS function
253 | ;
254 | SMWRITEBLOCK:
255 | JSR TRANSLATE
256 | BCC @WRITE
257 | RTS
258 |
259 | @WRITE: LDX SLOT16
260 | LDY SLOT
261 | JMP WRITE ; call ProDOS write
262 |
263 |
264 | ; Translates the Smartport unit number to a ProDOS device
265 | ; and prepares the block number
266 | ;
267 | ; Unit 0: entire chain, not supported
268 | ; Unit 1: this slot, drive 0
269 | ; Unit 2: this slot, drive 1
270 | ; Unit 3: phantom slot, drive 0
271 | ; Unit 4: phantom slot, drive 1
272 | ;
273 | TRANSLATE: LDA DRVNUM,Y
274 | BEQ @BADUNIT ; not supportd for unit 0
275 | CMP #1
276 | BEQ @UNIT1
277 | CMP #2
278 | BEQ @UNIT2
279 | CMP #3
280 | BEQ @UNIT3
281 | CMP #4
282 | BEQ @UNIT4
283 | BRA @BADUNIT ; only 4 partitions are supported
284 |
285 | @UNIT1: LDA SLOT16 ; this slot
286 | BRA @STORE
287 | @UNIT2: LDA SLOT16
288 | ORA #$80 ; drive 1
289 | BRA @STORE
290 | @UNIT3: LDA SLOT16
291 | DEC A ; phantom slot
292 | BRA @STORE
293 | @UNIT4: LDA SLOT16
294 | DEC A ; phantom slot
295 | ORA #$80 ; drive 1
296 |
297 | @STORE: STA DSNUMBER ; store in ProDOS variable
298 |
299 | LDY #2 ; get buffer pointer
300 | LDA (SMPARAMLIST),Y
301 | STA BUFFER
302 | INY
303 | LDA (SMPARAMLIST),Y
304 | STA BUFFER+1
305 |
306 | INY ; get block number
307 | LDA (SMPARAMLIST),Y
308 | STA BLOCKNUM
309 | INY
310 | LDA (SMPARAMLIST),Y
311 | STA BLOCKNUM+1
312 | INY
313 | LDA (SMPARAMLIST),Y
314 | BNE @BADBLOCK ; bit 23-16 need to be 0
315 |
316 | CLC
317 | RTS
318 |
319 | @BADUNIT: LDA #ERR_BADUNIT
320 | SEC
321 | RTS
322 |
323 | @BADBLOCK: LDA #ERR_BADBLOCK
324 | SEC
325 | RTS
326 |
327 |
328 | ; Smartport Format command
329 | ;
330 | ; supported, but doesn't do anything
331 | ; unit number must not be 0
332 | ;
333 | SMFORMAT: LDA DRVNUM,Y
334 | BEQ @ERROR
335 | LDA #NO_ERR
336 | CLC
337 | RTS
338 |
339 | @ERROR: LDA #ERR_BADUNIT
340 | SEC
341 | RTS
342 |
343 |
344 | ; Smartport Init comand
345 | ;
346 | ; supported, but doesn't do anything
347 | ; unit number must be 0
348 | ;
349 | SMINIT: LDA DRVNUM,Y
350 | CLC
351 | BEQ @END ; error if not 0
352 | LDA #ERR_BADUNIT
353 | SEC
354 | @END: RTS
355 |
356 |
357 | ; Smartport Open and Close commands
358 | ;
359 | ; supported for character devices, only
360 | ;
361 | SMOPEN:
362 | SMCLOSE: LDA #ERR_BADCMD
363 | SEC
364 | RTS
365 |
366 |
367 | ; Smartport Read Character and Write Character
368 | ;
369 | ; only 512-byte block operations are supported
370 | ;
371 | SMREADCHAR:
372 | SMWRITECHAR:
373 | LDA #ERR_IOERR
374 | SEC
375 | RTS
376 |
377 |
378 | ; Required parameter counts for the commands
379 | REQPARAMCOUNT:
380 | .byt 3 ; 0 = status
381 | .byt 3 ; 1 = read block
382 | .byt 3 ; 2 = write block
383 | .byt 1 ; 3 = format
384 | .byt 3 ; 4 = control
385 | .byt 1 ; 5 = init
386 | .byt 1 ; 6 = open
387 | .byt 1 ; 7 = close
388 | .byt 4 ; 8 = read char
389 | .byt 4 ; 9 = write char
390 |
391 | ; Command jump table
392 | SPDISPATCH:
393 | .word SMSTATUS
394 | .word SMREADBLOCK
395 | .word SMWRITEBLOCK
396 | .word SMFORMAT
397 | .word SMCONTROL
398 | .word SMINIT
399 | .word SMOPEN
400 | .word SMCLOSE
401 | .word SMREADCHAR
402 | .word SMWRITECHAR
403 |
404 | ; Status 00 command data
405 | STATUS00DATA:
406 | .byt $40 ; no interrupts
407 | .word $0000 ; unknown vendor
408 | .word SMDRIVERVER ; driver version
409 | .byt $00, $00 ; reserved
410 | .assert(*-STATUS00DATA)=7, error, "STATUS00DATA must be 7 bytes long"
411 |
412 | ; Status 3 command data
413 | STATUS3DATA:
414 | .byt 16, "APPLE][SD " ; ID length and string, padded
415 | .byt $02 ; hard disk
416 | .byt $00 ; removable hard disk
417 | .word SMDRIVERVER ; driver version
418 | .assert (*-STATUS3DATA)=21, error, "STATUS3DATA must be 21 bytes long"
419 |
--------------------------------------------------------------------------------
/Hardware/PCB-POOL Standard.dru:
--------------------------------------------------------------------------------
1 | description[de] = EAGLE Design Rules Prototypen für PCB-POOL(R)\n\nWir haben in diesem DRU File alle notwendigen Design Einstellungen vorgenommen, damit Sie Ihre Leiterplatte \ngemaess unseren Mindestanforderungen im Standard bestellen koennen. Die Optionen Shapes und Misc sind dabei nicht relevant.\nDer minimale und maximale Wert für Roundness Shapes kann frei gewählt werden.\nBitte beachten Sie, daß die Mindesteinstellungen nicht geaendert werden, da ansonsten keine Gewaehrleistung für eine \nfehlerfreie Produktion übernommen werden kann.
\nAbzudeckende Vias koennen in Masks (unter Limit) eingestellt werden.\n
Ihr Beta LAYOUT Team\n\nEAGLE Design Rules Prototypes to use with PCB-POOL(R)\n
\nThe design rules in this DRU file have been set to cover our minimum standard requirements, the options Shapes and Misc are not\nrelevant. Values for Roundness (Shapes) can be chosen freely. Please do not change these minimum\nrequirements to avoid problems during production.
\nCovered vias can be set in Masks (Limit).\n\n
Your Beta LAYOUT Team
2 | layerSetup = (1*16)
3 | mtCopper = 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm
4 | mtIsolate = 1.5mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm
5 | mdWireWire = 0.15mm
6 | mdWirePad = 0.15mm
7 | mdWireVia = 0.15mm
8 | mdPadPad = 0.15mm
9 | mdPadVia = 0.15mm
10 | mdViaVia = 0.15mm
11 | mdSmdPad = 0.15mm
12 | mdSmdVia = 0.15mm
13 | mdSmdSmd = 0.15mm
14 | mdViaViaSameLayer = 0.2mm
15 | mnLayersViaInSmd = 2
16 | mdCopperDimension = 0.3mm
17 | mdDrill = 0.2mm
18 | mdSmdStop = 0mil
19 | msWidth = 0.15mm
20 | msDrill = 0.3mm
21 | msMicroVia = 25mm
22 | msBlindViaRatio = 0.500000
23 | rvPadTop = 0.000000
24 | rvPadInner = 0.000000
25 | rvPadBottom = 0.000000
26 | rvViaOuter = 0.000000
27 | rvViaInner = 0.000000
28 | rvMicroViaOuter = 0.000000
29 | rvMicroViaInner = 0.000000
30 | rlMinPadTop = 0.2mm
31 | rlMaxPadTop = 2.5mm
32 | rlMinPadInner = 0.2mm
33 | rlMaxPadInner = 2.5mm
34 | rlMinPadBottom = 0.2mm
35 | rlMaxPadBottom = 2.5mm
36 | rlMinViaOuter = 0.15mm
37 | rlMaxViaOuter = 2.5mm
38 | rlMinViaInner = 0.2mm
39 | rlMaxViaInner = 2.5mm
40 | rlMinMicroViaOuter = 2.5mm
41 | rlMaxMicroViaOuter = 25mm
42 | rlMinMicroViaInner = 2.5mm
43 | rlMaxMicroViaInner = 25mm
44 | psTop = -1
45 | psBottom = -1
46 | psFirst = -1
47 | psElongationLong = 100
48 | psElongationOffset = 100
49 | mvStopFrame = 0.000000
50 | mvCreamFrame = 0.000000
51 | mlMinStopFrame = 0.075mm
52 | mlMaxStopFrame = 0.2mm
53 | mlMinCreamFrame = 0mil
54 | mlMaxCreamFrame = 0.2mm
55 | mlViaStopLimit = 0mil
56 | srRoundness = 0.000000
57 | srMinRoundness = 0mil
58 | srMaxRoundness = 0mil
59 | slThermalIsolate = 0.2mm
60 | slThermalsForVias = 0
61 | dpMaxLengthDifference = 10mm
62 | dpGapFactor = 2.500000
63 | checkGrid = 0
64 | checkAngle = 0
65 | checkFont = 1
66 | checkRestrict = 1
67 | useDiameter = 13
68 | maxErrors = 50
69 |
--------------------------------------------------------------------------------
/Hardware/SD_A2.gpi:
--------------------------------------------------------------------------------
1 | Generated by EAGLE CAM Processor 7.7.0
2 |
3 | Photoplotter Info File: //LUDWIG-FS/Vertrieb/TEMP/RZF/AppleIISd/SD_A2.gpi
4 |
5 | Date : 18.07.2017 10:31
6 | Plotfile : //LUDWIG-FS/Vertrieb/TEMP/RZF/AppleIISd/SD_A2.plc
7 | Apertures : generated:
8 | Device : Gerber RS-274-X photoplotter, coordinate format 2.5 inch
9 |
10 | Parameter settings:
11 |
12 | Emulate Apertures : no
13 | Tolerance Draw + : 0.00 %
14 | Tolerance Draw - : 0.00 %
15 | Tolerance Flash + : 0.00 %
16 | Tolerance Flash - : 0.00 %
17 | Rotate : no
18 | Mirror : no
19 | Optimize : yes
20 | Auto fit : yes
21 | OffsetX : 0inch
22 | OffsetY : 0inch
23 |
24 | Plotfile Info:
25 |
26 | Coordinate Format : 2.5
27 | Coordinate Units : Inch
28 | Data Mode : Absolute
29 | Zero Suppression : None
30 | End Of Block : *
31 |
32 | Apertures used:
33 |
34 | Code Shape Size used
35 |
36 | D10 draw 0.0040inch 398
37 | D11 draw 0.0060inch 196
38 | D12 draw 0.0050inch 90
39 | D13 rectangle 0.0400inch x 0.0750inch 1
40 | D14 rectangle 0.0700inch x 0.0150inch 1
41 | D15 rectangle 0.0500inch x 0.0100inch 1
42 | D16 rectangle 0.0300inch x 0.0100inch 1
43 | D17 square 0.0100inch 1
44 | D18 rectangle 0.0100inch x 0.0050inch 2
45 | D19 square 0.0050inch 8
46 | D20 draw 0.0020inch 4
47 | D21 rectangle 0.0350inch x 0.0500inch 3
48 | D22 draw 0.0070inch 37
49 | D23 rectangle 0.1000inch x 0.0100inch 1
50 | D24 draw 0.0030inch 10
51 |
52 |
--------------------------------------------------------------------------------
/Hardware/TagConnect.lbr:
--------------------------------------------------------------------------------
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 | >VALUE
91 | >NAME
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | >VALUE
109 | >NAME
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | >VALUE
131 | >NAME
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 | >VALUE
145 | >NAME
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 | >VALUE
161 | >NAME
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 | >VALUE
185 | >NAME
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 | Tag-Connect In Circuit Programming & Debug Cable 10 Pin
201 | http://www.tag-connect.com
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 | Tag-Connect In Circuit Programming & Debug Cable 6 Pin
244 | http://www.tag-connect.com
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
--------------------------------------------------------------------------------
/Hardware/con-sd-attend2.lbr:
--------------------------------------------------------------------------------
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 | >NAME
132 | >VALUE
133 | /CS
134 | Din
135 | GND
136 | VCC
137 | CLK
138 | GND
139 | Dout
140 | NC
141 | NC
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 | 104H-TDA0-R
173 | SD-CARD-SLOT
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
--------------------------------------------------------------------------------
/Hardware/lm1117.lbr:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freitz85/AppleIISd/b13ed9077f54387077b36edc959048bec4b9f689/Hardware/lm1117.lbr
--------------------------------------------------------------------------------
/Images/AddessDecoder_Test.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freitz85/AppleIISd/b13ed9077f54387077b36edc959048bec4b9f689/Images/AddessDecoder_Test.JPG
--------------------------------------------------------------------------------
/Images/AppleIISd_Test.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freitz85/AppleIISd/b13ed9077f54387077b36edc959048bec4b9f689/Images/AppleIISd_Test.JPG
--------------------------------------------------------------------------------
/Images/Bus1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freitz85/AppleIISd/b13ed9077f54387077b36edc959048bec4b9f689/Images/Bus1.gif
--------------------------------------------------------------------------------
/Images/Bus2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freitz85/AppleIISd/b13ed9077f54387077b36edc959048bec4b9f689/Images/Bus2.gif
--------------------------------------------------------------------------------
/Images/Card Front SMD.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freitz85/AppleIISd/b13ed9077f54387077b36edc959048bec4b9f689/Images/Card Front SMD.jpg
--------------------------------------------------------------------------------
/Images/Card Front.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freitz85/AppleIISd/b13ed9077f54387077b36edc959048bec4b9f689/Images/Card Front.jpg
--------------------------------------------------------------------------------
/Images/Spi1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freitz85/AppleIISd/b13ed9077f54387077b36edc959048bec4b9f689/Images/Spi1.png
--------------------------------------------------------------------------------
/Images/Spi2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/freitz85/AppleIISd/b13ed9077f54387077b36edc959048bec4b9f689/Images/Spi2.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AppleIISd
2 | SD card based ProFile replacement for enhanced Apple IIe and IIgs computers
3 |
4 | The **AppleIISd** is a SD card based replaced for the ProFile harddrive. In contrast to other SD card based devices, this card does not replace a Disk II drive. Data is saved directly onto the SD card, not via images on a FAT system, like on other cards. The SD card is accessable with [CiderPress](http://a2ciderpress.com/).
5 |
6 | A Xilinx CPLD is used as a SPI controller and translates, together with the ROM driver, SD card data to/from the Apple IIe. The VHDL source is based on [SPI65/B](http://www.6502.org/users/andre/spi65b) by André Fachat.
7 |
8 | The assembler sources are written for CC65. The [schematics](Binary/AppleIISd.pdf) are available as PDF.
9 |
10 | ## Features
11 | * works with ProDOS and GS/OS
12 | * up to 128MB storage space (4x 65535 blocks)
13 | * ProDOS and Smartport driver in ROM
14 | * Firmware update from ProDOS
15 | * Auto boot
16 | * Access LED
17 | * Card detect and write protect sensing
18 | * Skip boot when Open-Apple key is pressed
19 |
20 | ## Requirements
21 | The AppleIISd requires an enhanced IIe or IIgs computer. The ROM code uses some 65c02 opcodes and will therefore not work on a II, II+ or unenhanced IIe. It has been tested in the following combinations:
22 | * Apple IIgs Rom 01, GS/OS 6.0.4
23 | * Apple IIgs Rom 01, Prodos 2.4.1
24 | * Apple IIgs Rom 01, Prodos 1.9
25 | * Apple IIe enhanced, 128k, Prodos 2.4.1
26 | * Apple IIe enhanced, 128k, Prodos 1.9
27 | * Apple IIe enhanced, 64k, Prodos 1.9
28 |
29 | ## Binary distribution
30 | The following files in [Binary/](Binary) have been provided to eliminate the need to compile assembler or VHDL sources.
31 |
32 | | File | Purpose |
33 | | ---- | ------- |
34 | | AppleIISd_xx44.jed | CPLD bitfiles for PC44 and VQ44 formfactors |
35 | | AppleIISd.bin | 2k Firmware binary for EPROM |
36 | | AppleIISd.hex | Same as above in INTEL-HEX format |
37 | | AppleIISd.bom.txt | BOM for the board |
38 | | AppleIISd.pdf | Schematic and layout |
39 | | Flasher.bin | Flasher program ProDOS binary |
40 | | Flasher.dsk | Complete ProDOS disk image with Flasher.bin and AppleIISd.bin |
41 | | Gerber_Vx.x.zip | Gerber files for different hw revisions |
42 |
43 | ## Smartport drive remapping
44 | The AppleIISd features Smartport drivers in ROM to provide more than two drives in both GS/OS and ProDOS.
45 |
46 | As ProDOS supports only two drives per slot, additional drives on a Smartport device are mapped to 'phantom slots'. Version prior to version 2 supported only the remapping of drives when the card was in slot 5. Starting with version 2, the remapping seems to work on all slots. The following list shows the assignments as slot/drive, when no other devices are attached:
47 |
48 | * Slot 7: 7/1, 7/2, 4/1, 4/2
49 | * Slot 6: 6/1, 6/2, 4/1, 4/1
50 | * Slot 5: 5/1, 5/2, 2/1, 2/1
51 | * Slot 4: 4/1, 4/2, 1/1, 1/2
52 | * Slot 3: 80 col HW, not usable
53 | * Slot 2: 2/1, 2/2, 4/1, 4/2
54 | * Slot 1: 1/1, 1/2, 4/1, 4/2
55 |
56 | When more devices are connected, things get a little confusing ;-)
57 |
58 | ## Building the sources
59 | Be sure to have the newest version of CC65 (V2.16) and some kind of Make instaled, then type one of the following comands:
60 | ```
61 | make # generate binaries
62 | make OPTIONS=mapfile,listing # generate mapfile and listing, too
63 | make clean # delete binaries
64 | ```
65 | Alternatively use the VisualStudio solution.
66 |
67 | ## Timing
68 | The clock of the SPI bus *SCK* may be derived from either *Phi0* or the *7M* clock. Additionally, the divisor may be 2 to 8.
69 |
70 | The following measurements were taken with the divisor set to 2, resulting in *fSCK* of 500kHz and 3.5MHz. Reading of a byte requires that a dummy byte is sent on the bus, before the answer can be read. Therefore the measurement is the time between sending the byte and receiving the answer. The measurement for reading of a whole 512 byte block includes the SD card commands to do so.
71 |
72 | | Clock | Byte | Block | Image |
73 | | -----: | -----: | -----: | ------------------------------------------------: |
74 | | *Phi0* | 17.7µs | 28.8ms | [Byte](Images/Bus1.gif), [Block](Images/Spi1.png) |
75 | | *7M* | 3.9µs | 15ms | [Byte](Images/Bus2.gif), [Block](Images/Spi2.png) |
76 |
77 | This shows that the required to read a single byte can be reduced significantly by increasing *fSCK* (as one might have guessed). Reading at 500kHz actualy requires NOPs to be inserted (or checking the TC bit in the STATUS register), while reading at 3.5MHz can be done immediately.
78 |
79 | The time for reading a 512 byte block could *only* be halved, but there are for sure opportunities for optimization in the code surrounding the reading.
80 |
81 | ```
82 | * single byte @ 500kHz
83 | LDA #$FF
84 | STA $C0C0
85 | NOP
86 | NOP
87 | NOP
88 | NOP
89 | NOP
90 | NOP
91 | NOP
92 | LDA $C0C0
93 |
94 | * single byte @ 3.5MHz
95 | LDA #$FF
96 | STA $C0C0
97 | LDA $C0C0
98 | ```
99 |
100 |
101 | ## Registers
102 | The control registers of the *AppleIISd* are mapped to the usual I/O space at **$C0n0 - $C0n3**, where n is slot+8. All registers and bits are read/write, except where noted.
103 |
104 | | Address | Function | Default value |
105 | | ------- | --------------- | ------------- |
106 | | $C0n0 | DATA | - |
107 | | $C0n1 | **0:** PGMEN
**1:** -
**2:** ECE
**3:** -
**4:** FRX
**5:** BSY (R)
**6:** -
**7:** TC (R) | 0
0
0
0
0
0
0
0
|
108 | | $C0n2 | unused | $00 |
109 | | $C0n3 | **0:** /SS
**1:** -
**2:** -
**3:** -
**4:** SDHC
**5:** WP (R)
**6:** CD (R)
**7:** INIT | 1
0
0
0
0
-
-
0 |
110 |
111 | **DATA** SPI data register - Is used for both input and output. When the register is written to, the controller will output the byte on the SPI bus. When it is read from, it reflects the data that was received over the SPI bus.
112 |
113 | **PGMEN** Program Enable - Enable programing of the internal firmware eeprom. Should be reset immediately after writing to the device.
114 |
115 | **ECE** External Clock Enable - This bit enables the the external clock input to the SPI controller. In the *AppleIISd*, this effectively switches the SPI clock between 500kHz (ECE = 0) and 3.5MHz (ECE = 1).
116 |
117 | **FRX** Fast Receive mode - When set to 1, fast receive mode triggers shifting upon reading or writing the SPI Data register. When set to 0, shifting is only triggered by writing the SPI data register.
118 |
119 | **BSY** Busy - This bit is 1 as long as data is shifted out on the SPI bus. *BSY* is read-only.
120 |
121 | **TC** Transfer Complete - This flag is set when the last bit has been shifted out onto the SPI bus and is cleared when *SPI data* is read.
122 |
123 | **/SS** Slave select - Write 0 to this bit to select the SD card.
124 |
125 | **SDHC** This bit is used by the initialization routine in firmware to signalize when a SDHC card was found. Do not write to manually.
126 |
127 | **WP** Write Protect - This read-only bit is 0 when writing to the card is enabled by the switch on the card.
128 |
129 | **CD** Card Detect - This read-only bit is 0 when a card is inserted.
130 |
131 | **INIT** Initialized - This bit is set to 1 when the SD card has been initialized by the firmware. Do not write manually.
132 |
133 | ## TODOs
134 | * Much more testing
135 | * Enable more than 4 volumes under GS/OS
136 | * Support for 6502 CPUs
137 | * Support for CP/M
138 |
139 | ## Known Bugs
140 | * Programs not startable from partitions 3 and 4 under ProDOS
141 |
142 |
143 | 
144 | 
145 |
--------------------------------------------------------------------------------
/Software/Flasher.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | {B2CF2E9D-62A7-4A68-9477-9B15A8707E78}
27 | MakeFileProj
28 | Flasher
29 |
30 |
31 |
32 | Makefile
33 | true
34 | v140
35 |
36 |
37 | Makefile
38 | false
39 | v140
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | __APPLE2__;__APPLE2ENH__;__fastcall__=__fastcall;_MSC_VER=0;__attribute__
55 | $(PATH);C:\cc65\bin
56 | C:\cc65\include
57 | C:\cc65\lib
58 |
59 |
60 | $(MAKE_HOME)\make OPTIONS=mapfile,listing
61 | $(ProjectDir)\src
62 | $(MAKE_HOME)\make clean
63 | $(MAKE_HOME)\make OPTIONS=mapfile,listing
64 | $(SolutionDir)\
65 | $(MAKE_HOME)\make clean
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | del /S /Q "$(ProjectDir)makefile.options
74 | $(MAKE_HOME)\make -C "$(ProjectDir)\" PROGRAM="$(ProjectDir)$(Configuration)\$(ProjectName)"
75 | rmdir /S /Q "$(ProjectDir)obj\Win32"
76 | rmdir /S /Q "$(SolutionDir)Release"
77 | del /S /Q "$(ProjectDir)makefile.options
78 | $(MAKE_HOME)\make clean -C "$(ProjectDir)\" PROGRAM="$(ProjectDir)$(Configuration)\$(ProjectName)"
79 | $(MAKE_HOME)\make -C "$(ProjectDir)\" PROGRAM="$(ProjectDir)$(Configuration)\$(ProjectName)"
80 | rmdir /S /Q "$(ProjectDir)obj\Win32"
81 | rmdir /S /Q "$(SolutionDir)Release"
82 |
83 | del /S /Q "$(ProjectDir)makefile.options
84 | $(MAKE_HOME)\make clean -C "$(ProjectDir)\" PROGRAM="$(ProjectDir)$(Configuration)\$(ProjectName)"
85 | rmdir /S /Q "$(ProjectDir)obj\Win32"
86 | rmdir /S /Q "$(SolutionDir)Release"
87 | $(PATH);C:\cc65\bin
88 | $(VC_IncludePath);C:\cc65\include
89 |
90 | C:\cc65\lib
91 |
92 |
93 | $(SolutionDir)$\
94 |
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/Software/Flasher.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Software/apple2enh-system.cfg:
--------------------------------------------------------------------------------
1 | # Configuration for ProDOS 8 system programs (allowing for 3KB in LC)
2 |
3 | SYMBOLS {
4 | __EXEHDR__: type = import;
5 | __FILETYPE__: type = weak, value = $00FF; # ProDOS file type
6 | __STACKSIZE__: type = weak, value = $0800; # 2k stack
7 | __LCADDR__: type = weak, value = $D400; # Behind quit code
8 | __LCSIZE__: type = weak, value = $0C00; # Rest of bank two
9 | }
10 | MEMORY {
11 | ZP: file = "", define = yes, start = $0080, size = $001A;
12 | HEADER: file = %O, start = $2000 - $003A, size = $003A;
13 | MAIN: file = %O, define = yes, start = $2000, size = $BF00 - $2000;
14 | BSS: file = "", start = __ONCE_RUN__, size = $BF00 - __STACKSIZE__ - __ONCE_RUN__;
15 | LC: file = "", define = yes, start = __LCADDR__, size = __LCSIZE__;
16 | }
17 | SEGMENTS {
18 | ZEROPAGE: load = ZP, type = zp;
19 | EXEHDR: load = HEADER, type = ro, optional = yes;
20 | STARTUP: load = MAIN, type = ro;
21 | LOWCODE: load = MAIN, type = ro, optional = yes;
22 | CODE: load = MAIN, type = ro;
23 | RODATA: load = MAIN, type = ro;
24 | DATA: load = MAIN, type = rw;
25 | INIT: load = MAIN, type = rw;
26 | ONCE: load = MAIN, type = ro, define = yes;
27 | LC: load = MAIN, run = LC, type = ro, optional = yes;
28 | BSS: load = BSS, type = bss, define = yes;
29 | }
30 | FEATURES {
31 | CONDES: type = constructor,
32 | label = __CONSTRUCTOR_TABLE__,
33 | count = __CONSTRUCTOR_COUNT__,
34 | segment = ONCE;
35 | CONDES: type = destructor,
36 | label = __DESTRUCTOR_TABLE__,
37 | count = __DESTRUCTOR_COUNT__,
38 | segment = RODATA;
39 | CONDES: type = interruptor,
40 | label = __INTERRUPTOR_TABLE__,
41 | count = __INTERRUPTOR_COUNT__,
42 | segment = RODATA,
43 | import = __CALLIRQ__;
44 | }
45 |
--------------------------------------------------------------------------------
/Software/make_image.bat:
--------------------------------------------------------------------------------
1 | make clean
2 | make
3 | java -jar ..\Binary\AppleCommander-ac-1.5.0.jar -d ..\Binary\Flasher.dsk flasher
4 | java -jar ..\Binary\AppleCommander-ac-1.5.0.jar -as ..\Binary\Flasher.dsk flasher < Flasher.bin
5 | copy Flasher.bin ..\Binary
--------------------------------------------------------------------------------
/Software/make_image.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | make clean
4 | make
5 | java -jar ../Binary/AppleCommander-ac-1.5.0.jar -d ../Binary/Flasher.dsk flasher
6 | java -jar ../Binary/AppleCommander-ac-1.5.0.jar -as ../Binary/Flasher.dsk flasher < Flasher.bin
7 | cp Flasher.bin ../Binary/
8 |
--------------------------------------------------------------------------------
/Software/makefile:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | ### Generic Makefile for cc65 projects - full version with abstract options ###
3 | ### V1.3.0(w) 2010 - 2013 Oliver Schmidt & Patryk "Silver Dream !" ?ogiewa ###
4 | ###############################################################################
5 |
6 | ###############################################################################
7 | ### In order to override defaults - values can be assigned to the variables ###
8 | ###############################################################################
9 |
10 | # Space or comma separated list of cc65 supported target platforms to build for.
11 | # Default: c64 (lowercase!)
12 | TARGETS := apple2enh
13 |
14 | # Name of the final, single-file executable.
15 | # Default: name of the current dir with target name appended
16 | PROGRAM := Flasher
17 |
18 | # Path(s) to additional libraries required for linking the program
19 | # Use only if you don't want to place copies of the libraries in SRCDIR
20 | # Default: none
21 | LIBS :=
22 |
23 | # Custom linker configuration file
24 | # Use only if you don't want to place it in SRCDIR
25 | # Default: none
26 | CONFIG := apple2enh-system.cfg
27 |
28 | # Additional C compiler flags and options.
29 | # Default: none
30 | CFLAGS =
31 |
32 | # Additional assembler flags and options.
33 | # Default: none
34 | ASFLAGS =
35 |
36 | # Additional linker flags and options.
37 | # Default: none
38 | LDFLAGS =
39 |
40 | # Path to the directory containing C and ASM sources.
41 | # Default: src
42 | SRCDIR :=
43 |
44 | # Path to the directory where object files are to be stored (inside respective target subdirectories).
45 | # Default: obj
46 | OBJDIR :=
47 |
48 | # Command used to run the emulator.
49 | # Default: depending on target platform. For default (c64) target: x64 -kernal kernal -VICIIdsize -autoload
50 | EMUCMD :=
51 |
52 | # Optional commands used before starting the emulation process, and after finishing it.
53 | # Default: none
54 | # Examples
55 | #PREEMUCMD := osascript -e "tell application \"System Events\" to set isRunning to (name of processes) contains \"X11.bin\"" -e "if isRunning is true then tell application \"X11\" to activate"
56 | #PREEMUCMD := osascript -e "tell application \"X11\" to activate"
57 | #POSTEMUCMD := osascript -e "tell application \"System Events\" to tell process \"X11\" to set visible to false"
58 | #POSTEMUCMD := osascript -e "tell application \"Terminal\" to activate"
59 | PREEMUCMD :=
60 | POSTEMUCMD :=
61 |
62 | # On Windows machines VICE emulators may not be available in the PATH by default.
63 | # In such case, please set the variable below to point to directory containing
64 | # VICE emulators.
65 | #VICE_HOME := "C:\Program Files\WinVICE-2.2-x86\"
66 | VICE_HOME :=
67 |
68 | # Options state file name. You should not need to change this, but for those
69 | # rare cases when you feel you really need to name it differently - here you are
70 | STATEFILE := Makefile.options
71 |
72 | ###################################################################################
73 | #### DO NOT EDIT BELOW THIS LINE, UNLESS YOU REALLY KNOW WHAT YOU ARE DOING! ####
74 | ###################################################################################
75 |
76 | ###################################################################################
77 | ### Mapping abstract options to the actual compiler, assembler and linker flags ###
78 | ### Predefined compiler, assembler and linker flags, used with abstract options ###
79 | ### valid for 2.14.x. Consult the documentation of your cc65 version before use ###
80 | ###################################################################################
81 |
82 | # Compiler flags used to tell the compiler to optimise for SPEED
83 | define _optspeed_
84 | CFLAGS += -Oris
85 | endef
86 |
87 | # Compiler flags used to tell the compiler to optimise for SIZE
88 | define _optsize_
89 | CFLAGS += -Or
90 | endef
91 |
92 | # Compiler and assembler flags for generating listings
93 | define _listing_
94 | CFLAGS += --listing $$(@:.o=.lst) -T
95 | ASFLAGS += --listing $$(@:.o=.lst)
96 | REMOVES += $(addsuffix .lst,$(basename $(OBJECTS)))
97 | endef
98 |
99 | # Linker flags for generating map file
100 | define _mapfile_
101 | LDFLAGS += --mapfile $$@.map
102 | REMOVES += $(PROGRAM).map
103 | endef
104 |
105 | # Linker flags for generating VICE label file
106 | define _labelfile_
107 | LDFLAGS += -Ln $$@.lbl
108 | REMOVES += $(PROGRAM).lbl
109 | endef
110 |
111 | # Linker flags for generating a debug file
112 | define _debugfile_
113 | LDFLAGS += -Wl --dbgfile,$$@.dbg
114 | REMOVES += $(PROGRAM).dbg
115 | endef
116 |
117 | ###############################################################################
118 | ### Defaults to be used if nothing defined in the editable sections above ###
119 | ###############################################################################
120 |
121 | # Presume the C64 target like the cl65 compile & link utility does.
122 | # Set TARGETS to override.
123 | ifeq ($(TARGETS),)
124 | TARGETS := c64
125 | endif
126 |
127 | # Presume we're in a project directory so name the program like the current
128 | # directory. Set PROGRAM to override.
129 | ifeq ($(PROGRAM),)
130 | PROGRAM := $(notdir $(CURDIR))
131 | endif
132 |
133 | # Presume the C and asm source files to be located in the subdirectory 'src'.
134 | # Set SRCDIR to override.
135 | ifeq ($(SRCDIR),)
136 | SRCDIR := src
137 | endif
138 |
139 | # Presume the object and dependency files to be located in the subdirectory
140 | # 'obj' (which will be created). Set OBJDIR to override.
141 | ifeq ($(OBJDIR),)
142 | OBJDIR := obj
143 | endif
144 | TARGETOBJDIR := $(OBJDIR)
145 |
146 | # On Windows it is mandatory to have CC65_HOME set. So do not unnecessarily
147 | # rely on cl65 being added to the PATH in this scenario.
148 | ifdef CC65_HOME
149 | CC := $(CC65_HOME)/bin/cl65
150 | else
151 | CC := cl65
152 | endif
153 |
154 | # Default emulator commands and options for particular targets.
155 | # Set EMUCMD to override.
156 | c64_EMUCMD := $(VICE_HOME)x64 -kernal kernal -VICIIdsize -autoload
157 | c128_EMUCMD := $(VICE_HOME)x128 -kernal kernal -VICIIdsize -autoload
158 | vic20_EMUCMD := $(VICE_HOME)xvic -kernal kernal -VICdsize -autoload
159 | pet_EMUCMD := $(VICE_HOME)xpet -Crtcdsize -autoload
160 | plus4_EMUCMD := $(VICE_HOME)xplus4 -TEDdsize -autoload
161 | # So far there is no x16 emulator in VICE (why??) so we have to use xplus4 with -memsize option
162 | c16_EMUCMD := $(VICE_HOME)xplus4 -ramsize 16 -TEDdsize -autoload
163 | cbm510_EMUCMD := $(VICE_HOME)xcbm2 -model 510 -VICIIdsize -autoload
164 | cbm610_EMUCMD := $(VICE_HOME)xcbm2 -model 610 -Crtcdsize -autoload
165 | atari_EMUCMD := atari800 -windowed -xl -pal -nopatchall -run
166 |
167 | ifeq ($(EMUCMD),)
168 | EMUCMD = $($(CC65TARGET)_EMUCMD)
169 | endif
170 |
171 | ###############################################################################
172 | ### The magic begins ###
173 | ###############################################################################
174 |
175 | # The "Native Win32" GNU Make contains quite some workarounds to get along with
176 | # cmd.exe as shell. However it does not provide means to determine that it does
177 | # actually activate those workarounds. Especially $(SHELL) does NOT contain the
178 | # value 'cmd.exe'. So the usual way to determine if cmd.exe is being used is to
179 | # execute the command 'echo' without any parameters. Only cmd.exe will return a
180 | # non-empty string - saying 'ECHO is on/off'.
181 | #
182 | # Many "Native Win32" programs accept '/' as directory delimiter just fine. How-
183 | # ever the internal commands of cmd.exe generally require '\' to be used.
184 | #
185 | # cmd.exe has an internal command 'mkdir' that doesn't understand nor require a
186 | # '-p' to create parent directories as needed.
187 | #
188 | # cmd.exe has an internal command 'del' that reports a syntax error if executed
189 | # without any file so make sure to call it only if there's an actual argument.
190 | ifeq ($(shell echo),)
191 | MKDIR = mkdir -p $1
192 | RMDIR = rmdir $1
193 | RMFILES = $(RM) $1
194 | else
195 | MKDIR = mkdir $(subst /,\,$1)
196 | RMDIR = rmdir $(subst /,\,$1)
197 | RMFILES = $(if $1,del /f $(subst /,\,$1))
198 | endif
199 | COMMA := ,
200 | SPACE := $(N/A) $(N/A)
201 | define NEWLINE
202 |
203 |
204 | endef
205 | # Note: Do not remove any of the two empty lines above !
206 |
207 | TARGETLIST := $(subst $(COMMA),$(SPACE),$(TARGETS))
208 |
209 | ifeq ($(words $(TARGETLIST)),1)
210 |
211 | # Set PROGRAM to something like 'myprog.c64'.
212 | override PROGRAM := $(PROGRAM).bin
213 |
214 | # Set SOURCES to something like 'src/foo.c src/bar.s'.
215 | # Use of assembler files with names ending differently than .s is deprecated!
216 | SOURCES := $(wildcard $(SRCDIR)/*.c)
217 | SOURCES += $(wildcard $(SRCDIR)/*.s)
218 | SOURCES += $(wildcard $(SRCDIR)/*.asm)
219 | SOURCES += $(wildcard $(SRCDIR)/*.a65)
220 |
221 | # Add to SOURCES something like 'src/c64/me.c src/c64/too.s'.
222 | # Use of assembler files with names ending differently than .s is deprecated!
223 | SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.c)
224 | SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.s)
225 | SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.asm)
226 | SOURCES += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.a65)
227 |
228 | # Set OBJECTS to something like 'obj/c64/foo.o obj/c64/bar.o'.
229 | OBJECTS := $(addsuffix .o,$(basename $(addprefix $(TARGETOBJDIR)/,$(notdir $(SOURCES)))))
230 |
231 | # Set DEPENDS to something like 'obj/c64/foo.d obj/c64/bar.d'.
232 | DEPENDS := $(OBJECTS:.o=.d)
233 |
234 | # Add to LIBS something like 'src/foo.lib src/c64/bar.lib'.
235 | LIBS += $(wildcard $(SRCDIR)/*.lib)
236 | LIBS += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.lib)
237 |
238 | # Add to CONFIG something like 'src/c64/bar.cfg src/foo.cfg'.
239 | CONFIG += $(wildcard $(SRCDIR)/$(TARGETLIST)/*.cfg)
240 | CONFIG += $(wildcard $(SRCDIR)/*.cfg)
241 |
242 | # Select CONFIG file to use. Target specific configs have higher priority.
243 | ifneq ($(word 2,$(CONFIG)),)
244 | CONFIG := $(firstword $(CONFIG))
245 | $(info Using config file $(CONFIG) for linking)
246 | endif
247 |
248 | .SUFFIXES:
249 | .PHONY: all test clean zap love
250 |
251 | all: $(PROGRAM)
252 |
253 | -include $(DEPENDS)
254 | -include $(STATEFILE)
255 |
256 | # If OPTIONS are given on the command line then save them to STATEFILE
257 | # if (and only if) they have actually changed. But if OPTIONS are not
258 | # given on the command line then load them from STATEFILE. Have object
259 | # files depend on STATEFILE only if it actually exists.
260 | ifeq ($(origin OPTIONS),command line)
261 | ifneq ($(OPTIONS),$(_OPTIONS_))
262 | ifeq ($(OPTIONS),)
263 | $(info Removing OPTIONS)
264 | $(shell $(RM) $(STATEFILE))
265 | $(eval $(STATEFILE):)
266 | else
267 | $(info Saving OPTIONS=$(OPTIONS))
268 | $(shell echo _OPTIONS_=$(OPTIONS) > $(STATEFILE))
269 | endif
270 | $(eval $(OBJECTS): $(STATEFILE))
271 | endif
272 | else
273 | ifeq ($(origin _OPTIONS_),file)
274 | $(info Using saved OPTIONS=$(_OPTIONS_))
275 | OPTIONS = $(_OPTIONS_)
276 | $(eval $(OBJECTS): $(STATEFILE))
277 | endif
278 | endif
279 |
280 | # Transform the abstract OPTIONS to the actual cc65 options.
281 | $(foreach o,$(subst $(COMMA),$(SPACE),$(OPTIONS)),$(eval $(_$o_)))
282 |
283 | # Strip potential variant suffix from the actual cc65 target.
284 | CC65TARGET := $(firstword $(subst .,$(SPACE),$(TARGETLIST)))
285 |
286 | # The remaining targets.
287 | $(TARGETOBJDIR):
288 | $(call MKDIR,$@)
289 |
290 | vpath %.c $(SRCDIR)/$(TARGETLIST) $(SRCDIR)
291 |
292 | $(TARGETOBJDIR)/%.o: %.c | $(TARGETOBJDIR)
293 | $(CC) -t $(CC65TARGET) -c --create-dep $(@:.o=.d) $(CFLAGS) -o $@ $<
294 |
295 | vpath %.s $(SRCDIR)/$(TARGETLIST) $(SRCDIR)
296 |
297 | $(TARGETOBJDIR)/%.o: %.s | $(TARGETOBJDIR)
298 | $(CC) -t $(CC65TARGET) -c --create-dep $(@:.o=.d) $(ASFLAGS) -o $@ $<
299 |
300 | vpath %.asm $(SRCDIR)/$(TARGETLIST) $(SRCDIR)
301 |
302 | $(TARGETOBJDIR)/%.o: %.asm | $(TARGETOBJDIR)
303 | $(CC) -t $(CC65TARGET) -c --create-dep $(@:.o=.d) $(ASFLAGS) -o $@ $<
304 |
305 | vpath %.a65 $(SRCDIR)/$(TARGETLIST) $(SRCDIR)
306 |
307 | $(TARGETOBJDIR)/%.o: %.a65 | $(TARGETOBJDIR)
308 | $(CC) -t $(CC65TARGET) -c --create-dep $(@:.o=.d) $(ASFLAGS) -o $@ $<
309 |
310 | $(PROGRAM): $(CONFIG) $(OBJECTS) $(LIBS)
311 | $(CC) -t $(CC65TARGET) $(LDFLAGS) -o $@ $(patsubst %.cfg,-C %.cfg,$^)
312 |
313 | test: $(PROGRAM)
314 | $(PREEMUCMD)
315 | $(EMUCMD) $<
316 | $(POSTEMUCMD)
317 |
318 | clean:
319 | $(call RMFILES,$(OBJECTS))
320 | $(call RMFILES,$(DEPENDS))
321 | $(call RMFILES,$(REMOVES))
322 | $(call RMFILES,$(PROGRAM))
323 |
324 | else # $(words $(TARGETLIST)),1
325 |
326 | all test clean:
327 | $(foreach t,$(TARGETLIST),$(MAKE) TARGETS=$t $@$(NEWLINE))
328 |
329 | endif # $(words $(TARGETLIST)),1
330 |
331 | OBJDIRLIST := $(wildcard $(OBJDIR)/*)
332 |
333 | zap:
334 | $(foreach o,$(OBJDIRLIST),-$(call RMFILES,$o/*.o $o/*.d $o/*.lst)$(NEWLINE))
335 | $(foreach o,$(OBJDIRLIST),-$(call RMDIR,$o)$(NEWLINE))
336 | -$(call RMDIR,$(OBJDIR))
337 | -$(call RMFILES,$(basename $(PROGRAM)).* $(STATEFILE))
338 |
339 | love:
340 | @echo "Not war, eh?"
341 |
342 | ###################################################################
343 | ### Place your additional targets in the additional Makefiles ###
344 | ### in the same directory - their names have to end with ".mk"! ###
345 | ###################################################################
346 | -include *.mk
--------------------------------------------------------------------------------
/Software/src/AppleIISd.h:
--------------------------------------------------------------------------------
1 | #ifndef APPLE_II_SD_H
2 | #define APPLE_II_SD_H
3 |
4 | typedef unsigned char uint8;
5 | typedef unsigned short uint16;
6 | typedef unsigned long uint32;
7 | typedef unsigned char boolean;
8 |
9 | #ifndef TRUE
10 | #define TRUE 1
11 | #endif
12 | #ifndef FALSE
13 | #define FALSE 0
14 | #endif
15 |
16 | #define SLOT_IO_START (volatile uint8*)0xC080
17 | #define SLOT_ROM_START (volatile uint8*)0xC000
18 | #define EXT_ROM_START (volatile uint8*)0xC800
19 |
20 | #define CFFF (volatile uint8*)0xCFFF
21 |
22 | typedef volatile struct
23 | {
24 | // data register
25 | // +0
26 | uint8 data;
27 |
28 | // status register
29 | // +1
30 | union
31 | {
32 | struct
33 | {
34 | unsigned pgmen : 1;
35 | unsigned : 1;
36 | unsigned ece : 1;
37 | unsigned : 1;
38 | unsigned frx : 1;
39 | const unsigned bsy : 1;
40 | unsigned : 1;
41 | const unsigned tc : 1;
42 | };
43 |
44 | uint8 status;
45 | } status;
46 |
47 | // clock divisor register, unused
48 | // +2
49 | uint8 clkDiv;
50 |
51 | // slave select and card state register
52 | // +3
53 | union
54 | {
55 | struct
56 | {
57 | unsigned slaveSel : 1;
58 | unsigned : 3;
59 | unsigned sdhc : 1;
60 | const unsigned wp : 1;
61 | const unsigned card : 1;
62 | unsigned inited : 1;
63 | };
64 |
65 | uint8 ss_card;
66 | } ss_card;
67 | } APPLE_II_SD_T;
68 |
69 | #endif
70 |
--------------------------------------------------------------------------------
/Software/src/Flasher.c:
--------------------------------------------------------------------------------
1 | #include "AppleIISd.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | // Binary can't be larger than 2k
11 | #define BUFFER_SIZE 2048
12 | #define BIN_FILE_NAME "AppleIISd.bin"
13 |
14 | typedef enum
15 | {
16 | STATE_0, // pipe
17 | STATE_1, // slash
18 | STATE_2, // hyphen
19 | STATE_3, // backslash
20 |
21 | STATE_LAST // don't use
22 | } STATE_CURSOR_T;
23 |
24 | const char state_char[STATE_LAST] = { '|', '/', '-', '\\' };
25 | static uint8 buffer[BUFFER_SIZE];
26 |
27 | static void writeChip(const uint8* pSource, volatile uint8* pDest, uint16 length);
28 | static boolean verifyChip(const uint8* pSource, volatile uint8* pDest, uint16 length);
29 | static void printStatus(uint8 percentage);
30 |
31 | int main()
32 | {
33 | int retval = 1;
34 | FILE* pFile;
35 | char slotNum;
36 | boolean erase = FALSE;
37 | uint16 fileSize = 0;
38 |
39 | APPLE_II_SD_T* pAIISD;
40 | volatile uint8* pSlotRom = SLOT_ROM_START;
41 | volatile uint8 dummy;
42 |
43 | videomode(VIDEOMODE_40COL);
44 | clrscr();
45 | cprintf("AppleIISd firmware flasher V1.2\r\n");
46 | cprintf("(c) 2019-2020 Florian Reitz\r\n\r\n");
47 |
48 | // ask for slot
49 | cursor(1); // enable blinking cursor
50 | cprintf("Slot number (1-7): ");
51 | cscanf("%c", &slotNum);
52 | slotNum -= 0x30;
53 | cursor(0); // disable blinking cursor
54 |
55 | if(slotNum == 0)
56 | {
57 | // erase device
58 | erase = TRUE;
59 | // ask for slot
60 | cursor(1); // enable blinking cursor
61 | cprintf("Erase device in slot number (1-7): ");
62 | cscanf("%c", &slotNum);
63 | slotNum -= 0x30;
64 | cursor(0); // disable blinking cursor
65 | }
66 |
67 | // check if slot is valid
68 | if((slotNum < 1) || (slotNum > 7))
69 | {
70 | cprintf("\r\nInvalid slot number!");
71 | cgetc();
72 | return 1; // failure
73 | }
74 |
75 | pAIISD = (APPLE_II_SD_T*)(SLOT_IO_START + (slotNum << 4));
76 | pSlotRom += slotNum << 8;
77 |
78 | if(erase)
79 | {
80 | fileSize = BUFFER_SIZE;
81 | memset(buffer, 0, sizeof(buffer));
82 | }
83 | else
84 | {
85 | // open file
86 | pFile = fopen(BIN_FILE_NAME, "rb");
87 | if(pFile)
88 | {
89 | // read buffer
90 | fileSize = fread(buffer, 1, sizeof(buffer), pFile);
91 | fclose(pFile);
92 | pFile = NULL;
93 |
94 | if(fileSize != BUFFER_SIZE)
95 | {
96 | cprintf("\r\nWrong file size: %d\r\n", fileSize);
97 | }
98 | }
99 | else
100 | {
101 | cprintf("\r\nCan't open %s file\r\n", BIN_FILE_NAME);
102 | fileSize = 0;
103 | }
104 | }
105 |
106 | if(fileSize == BUFFER_SIZE)
107 | {
108 | // enable write
109 | pAIISD->status.pgmen = 1;
110 |
111 | // write to SLOTROM
112 | cprintf("\r\n\r\nFlashing SLOTROM: ");
113 | writeChip(buffer, pSlotRom, 256);
114 |
115 | cprintf("\r\nVerifying SLOTROM: ");
116 | if(verifyChip(buffer, pSlotRom, 256))
117 | {
118 | // write to EXT_ROM
119 | cprintf("\r\n\r\nFlashing EXTROM: ");
120 |
121 | // clear CFFF and dummy read to enable correct EXT_ROM
122 | dummy = *CFFF;
123 | dummy = *pSlotRom;
124 |
125 | writeChip(buffer + 256, EXT_ROM_START, fileSize - 256);
126 | cprintf("\r\nVerifying EXTROM: ");
127 |
128 | dummy = *CFFF;
129 | dummy = *pSlotRom;
130 |
131 | if(verifyChip(buffer + 256, EXT_ROM_START, fileSize - 256))
132 | {
133 | cprintf("\r\n\r\nFlashing finished!\n");
134 | retval = 0;
135 | }
136 | }
137 |
138 | // disable write
139 | pAIISD->status.pgmen = 0;
140 | }
141 |
142 | cgetc();
143 | return retval;
144 | }
145 |
146 | static void writeChip(const uint8* pSource, volatile uint8* pDest, uint16 length)
147 | {
148 | uint32 i;
149 | volatile uint8 readData;
150 |
151 | for(i=0; i A,
88 | B => B,
89 | CLK => CLK,
90 | PHI0 => PHI0,
91 | RNW => RNW,
92 | NDEV_SEL => NDEV_SEL,
93 | NIO_SEL => NIO_SEL,
94 | NIO_STB => NIO_STB,
95 | NRESET => NRESET,
96 | DATA_EN => DATA_EN,
97 | PGM_EN => PGM_EN,
98 | NG => NG,
99 | NOE => NOE,
100 | NWE => NWE
101 | );
102 |
103 | -- Clock process definitions
104 | CLK_process :process
105 | begin
106 | CLK <= '0';
107 | wait for CLK_period/2;
108 | CLK <= '1';
109 | wait for CLK_period/2;
110 | end process;
111 |
112 | PHI0_process :process(CLK)
113 | variable counter : integer range 0 to 7;
114 | begin
115 | if rising_edge(CLK) or falling_edge(CLK) then
116 | counter := counter + 1;
117 | if counter = 7 then
118 | PHI0 <= not PHI0;
119 | counter := 0;
120 | end if;
121 | end if;
122 | end process;
123 |
124 | -- Stimulus process
125 | stim_proc: process
126 | begin
127 | -- hold reset state.
128 | wait for CLK_period * 10;
129 | NRESET <= '0';
130 | wait for CLK_period * 20;
131 | NRESET <= '1';
132 | wait for CLK_period * 10;
133 |
134 | -- C0nX access
135 | -- NG must be '0"
136 | -- NOE must be '1'
137 | -- NWE must be '1'
138 | A <= "0000"; -- must become "000"
139 | wait until rising_edge(PHI0);
140 | NDEV_SEL <= '0';
141 | wait until falling_edge(PHI0);
142 | assert (B="000") report "Address error" severity error;
143 | assert (NG='0') report "NG error" severity error;
144 | assert (NOE='1') report "NOE error" severity error;
145 | assert (NWE='1') report "NWE error" severity error;
146 | NDEV_SEL <= '1';
147 | wait until rising_edge(PHI0);
148 | assert (NG='1') report "NG error" severity error;
149 | assert (NOE='1') report "NOE error" severity error;
150 | assert (NWE='1') report "NWE error" severity error;
151 |
152 | -- C0nX access, write
153 | -- NG must be '0"
154 | -- NOE must be '1'
155 | -- NWE must be '1'
156 | RNW <= '0';
157 | A <= "0000"; -- must become "000"
158 | wait until rising_edge(PHI0);
159 | NDEV_SEL <= '0';
160 | wait until falling_edge(PHI0);
161 | assert (B="000") report "Address error" severity error;
162 | assert (NG='0') report "NG error" severity error;
163 | assert (NOE='1') report "NOE error" severity error;
164 | assert (NWE='1') report "NWE error" severity error;
165 | NDEV_SEL <= '1';
166 | wait until rising_edge(PHI0);
167 |
168 | -- CnXX access, select
169 | -- NG must be '0'
170 | -- NOE must be '0'
171 | -- NWE must be '1'
172 | RNW <= '1';
173 | A <= "0100"; -- must become "000"
174 | wait until rising_edge(PHI0);
175 | NIO_SEL <= '0';
176 | wait until falling_edge(PHI0);
177 | assert (B="000") report "Address error" severity error;
178 | assert (NG='0') report "NG error" severity error;
179 | assert (NOE='0') report "NOE error" severity error;
180 | assert (NWE='1') report "NWE error" severity error;
181 | NIO_SEL <= '1';
182 | wait until rising_edge(PHI0);
183 |
184 | -- CnXX access, write, select
185 | -- NG must be '0'
186 | -- NOE must be '1'
187 | -- NWE must be '0'
188 | RNW <= '0';
189 | A <= "0100"; -- must become "000"
190 | wait until rising_edge(PHI0);
191 | NIO_SEL <= '0';
192 | wait until falling_edge(PHI0);
193 | assert (B="000") report "Address error" severity error;
194 | assert (NG='0') report "NG error" severity error;
195 | assert (NOE='1') report "NOE error" severity error;
196 | assert (NWE='0') report "NWE error" severity error;
197 | NIO_SEL <= '1';
198 | wait until rising_edge(PHI0);
199 |
200 | -- CnXX access, write, select, no PGM_EN
201 | -- NG must be '0'
202 | -- NOE must be '1'
203 | -- NWE must be '1'
204 | RNW <= '0';
205 | PGM_EN <= '0';
206 | A <= "0100"; -- must become "000"
207 | wait until rising_edge(PHI0);
208 | NIO_SEL <= '0';
209 | wait until falling_edge(PHI0);
210 | assert (B="000") report "Address error" severity error;
211 | assert (NG='0') report "NG error" severity error;
212 | assert (NOE='1') report "NOE error" severity error;
213 | assert (NWE='1') report "NWE error" severity error;
214 | NIO_SEL <= '1';
215 | wait until rising_edge(PHI0);
216 |
217 | -- C8xx access, selected
218 | -- NG must be '0'
219 | -- NOE must be '0'
220 | -- NWE must be '1'
221 | RNW <= '1';
222 | PGM_EN <= '1';
223 | A <= "1000"; -- must become "001"
224 | wait until rising_edge(PHI0);
225 | NIO_STB <= '0';
226 | wait until falling_edge(PHI0);
227 | assert (B="001") report "Address error" severity error;
228 | assert (NG='0') report "NG error" severity error;
229 | assert (NOE='0') report "NOE error" severity error;
230 | assert (NWE='1') report "NWE error" severity error;
231 | NIO_STB <= '1';
232 | wait until rising_edge(PHI0);
233 |
234 | -- C8xx write access, selected
235 | -- NG must be '0'
236 | -- NOE must be '1'
237 | -- NWE must be '0'
238 | RNW <= '0';
239 | wait until rising_edge(PHI0);
240 | NIO_STB <= '0';
241 | wait until falling_edge(PHI0);
242 | assert (NG='0') report "NG error" severity error;
243 | assert (NOE='1') report "NOE error" severity error;
244 | assert (NWE='0') report "NWE error" severity error;
245 | NIO_STB <= '1';
246 | wait until rising_edge(PHI0);
247 |
248 | -- C9xx access, selected
249 | -- NG must be '0'
250 | -- NOE must be '0'
251 | -- NWE must be '1'
252 | RNW <= '1';
253 | A <= "1001"; -- must become "010"
254 | wait until rising_edge(PHI0);
255 | NIO_STB <= '0';
256 | wait until falling_edge(PHI0);
257 | assert (B="010") report "Address error" severity error;
258 | assert (NG='0') report "NG error" severity error;
259 | assert (NOE='0') report "NOE error" severity error;
260 | assert (NWE='1') report "NWE error" severity error;
261 | NIO_STB <= '1';
262 | wait until rising_edge(PHI0);
263 |
264 | -- C9xx access write, selected
265 | -- NG must be '0'
266 | -- NOE must be '1'
267 | -- NWE must be '0'
268 | RNW <= '0';
269 | wait until rising_edge(PHI0);
270 | NIO_STB <= '0';
271 | wait until falling_edge(PHI0);
272 | assert (NG='0') report "NG error" severity error;
273 | assert (NOE='1') report "NOE error" severity error;
274 | assert (NWE='0') report "NWE error" severity error;
275 | NIO_STB <= '1';
276 | wait until rising_edge(PHI0);
277 |
278 | -- CPLD access
279 | -- NG must be '0'
280 | -- NOE must be '1'
281 | -- NWE must be '1'
282 | RNW <= '1';
283 | A <= "0101"; -- must become "000"
284 | wait until rising_edge(PHI0);
285 | NDEV_SEL <= '0';
286 | wait until falling_edge(PHI0);
287 | assert (B="000") report "Address error" severity error;
288 | assert (NG='0') report "NG error" severity error;
289 | assert (NOE='1') report "NOE error" severity error;
290 | assert (NWE='1') report "NWE error" severity error;
291 | NDEV_SEL <= '1';
292 | wait until rising_edge(PHI0);
293 |
294 | -- CFFF access
295 | -- NG must be '1'
296 | -- NOE must be '1'
297 | -- NWE must be '1'
298 | A <= "1111"; -- must become "111"
299 | wait until rising_edge(PHI0);
300 | NIO_STB <= '0';
301 | wait until falling_edge(PHI0);
302 | assert (B="111") report "Address error" severity error;
303 | assert (NG='1') report "NG error" severity error;
304 | assert (NOE='1') report "NOE error" severity error;
305 | assert (NWE='1') report "NWE error" severity error;
306 | NIO_STB <= '1';
307 | wait until rising_edge(PHI0);
308 |
309 | -- C8xx access, unselected
310 | -- NG must be '1'
311 | -- NOE must be '1'
312 | -- NWE must be '1'
313 | A <= "1000"; -- must become "001"
314 | wait until rising_edge(PHI0);
315 | NIO_STB <= '0';
316 | wait until falling_edge(PHI0);
317 | assert (B="001") report "Address error" severity error;
318 | assert (NG='1') report "NG error" severity error;
319 | assert (NOE='1') report "NOE error" severity error;
320 | assert (NWE='1') report "NWE error" severity error;
321 | NIO_STB <= '1';
322 | wait until rising_edge(PHI0);
323 |
324 | -- C8xx access write, unselected
325 | -- NG must be '1'
326 | -- NOE must be '1'
327 | -- NWE must be '1'
328 | RNW <= '0';
329 | A <= "1000"; -- must become "001"
330 | wait until rising_edge(PHI0);
331 | NIO_STB <= '0';
332 | wait until falling_edge(PHI0);
333 | assert (B="001") report "Address error" severity error;
334 | assert (NG='1') report "NG error" severity error;
335 | assert (NOE='1') report "NOE error" severity error;
336 | assert (NWE='1') report "NWE error" severity error;
337 | NIO_STB <= '1';
338 | wait until rising_edge(PHI0);
339 |
340 | wait;
341 | end process;
342 |
343 | END;
344 |
--------------------------------------------------------------------------------
/VHDL/AppleIISd.vhd:
--------------------------------------------------------------------------------
1 | ----------------------------------------------------------------------------------
2 | -- Company:
3 | -- Engineer:
4 | --
5 | -- Create Date: 20:44:25 10/09/2017
6 | -- Design Name:
7 | -- Module Name: IO - Behavioral
8 | -- Project Name:
9 | -- Target Devices:
10 | -- Tool versions:
11 | -- Description:
12 | --
13 | -- Dependencies:
14 | --
15 | -- Revision:
16 | -- Revision 0.01 - File Created
17 | -- Additional Comments:
18 | --
19 | ----------------------------------------------------------------------------------
20 | library IEEE;
21 | use IEEE.STD_LOGIC_1164.ALL;
22 |
23 | -- Uncomment the following library declaration if using
24 | -- arithmetic functions with Signed or Unsigned values
25 | --use IEEE.NUMERIC_STD.ALL;
26 |
27 | -- Uncomment the following library declaration if instantiating
28 | -- any Xilinx primitives in this code.
29 | --library UNISIM;
30 | --use UNISIM.VComponents.all;
31 |
32 | entity AppleIISd is
33 | Port (
34 | ADD_HIGH : in std_logic_vector(11 downto 8);
35 | ADD_LOW : in std_logic_vector(1 downto 0);
36 | B : out std_logic_vector(10 downto 8);
37 | CARD : in std_logic;
38 | DATA : inout std_logic_vector (7 downto 0);
39 | CLK : in std_logic;
40 | LED : out std_logic;
41 | NDEV_SEL : in std_logic;
42 | NG : out std_logic;
43 | NIO_SEL : in std_logic;
44 | NIO_STB : in std_logic;
45 | NOE : out std_logic;
46 | NWE : out std_logic;
47 | PHI0 : in std_logic;
48 | NRESET : in std_logic;
49 | RNW : in std_logic;
50 | MISO : in std_logic;
51 | MOSI : out std_logic;
52 | NSEL : out std_logic;
53 | SCLK : out std_logic;
54 | WP : in std_logic
55 |
56 | -- synthesis translate_off
57 | ;
58 | data_dbg : out std_logic_vector (7 downto 0);
59 | add_dbg : out std_logic_vector (1 downto 0);
60 | data_en_dbg : out std_logic
61 | -- synthesis translate_on
62 |
63 | );
64 | end AppleIISd;
65 |
66 | architecture Behavioral of AppleIISd is
67 |
68 | signal data_in : std_logic_vector (7 downto 0);
69 | signal data_out : std_logic_vector (7 downto 0);
70 | signal addr_low_int : std_logic_vector (1 downto 0);
71 |
72 | signal data_en : std_logic;
73 | signal pgm_en : std_logic;
74 |
75 | component SpiController is
76 | Port (
77 | data_in : in std_logic_vector (7 downto 0);
78 | data_out : out std_logic_vector (7 downto 0);
79 | is_read : in std_logic;
80 | nreset : in std_logic;
81 | addr : in std_logic_vector (1 downto 0);
82 | phi0 : in std_logic;
83 | ndev_sel : in std_logic;
84 | clk : in std_logic;
85 | miso: in std_logic;
86 | mosi : out std_logic;
87 | sclk : out std_logic;
88 | nsel : out std_logic;
89 | wp : in std_logic;
90 | card : in std_logic;
91 | led : out std_logic;
92 | pgm_en : out std_logic
93 | );
94 | end component;
95 |
96 | component AddressDecoder
97 | Port (
98 | A : in std_logic_vector (11 downto 8);
99 | B : out std_logic_vector (10 downto 8);
100 | CLK : in std_logic;
101 | PHI0 : in std_logic;
102 | RNW : in std_logic;
103 | NDEV_SEL : in std_logic;
104 | NIO_SEL : in std_logic;
105 | NIO_STB : in std_logic;
106 | NRESET : in std_logic;
107 | DATA_EN : out std_logic;
108 | PGM_EN : in std_logic;
109 | NG : out std_logic;
110 | NOE : out std_logic;
111 | NWE : out std_logic
112 | );
113 | end component;
114 |
115 |
116 | begin
117 | spi: SpiController port map(
118 | data_in => data_in,
119 | data_out => data_out,
120 | is_read => RNW,
121 | nreset => NRESET,
122 | addr => addr_low_int,
123 | phi0 => PHI0,
124 | ndev_sel => NDEV_SEL,
125 | clk => CLK,
126 | miso => MISO,
127 | mosi => MOSI,
128 | sclk => SCLK,
129 | nsel => NSEL,
130 | wp => WP,
131 | card => CARD,
132 | led => LED,
133 | pgm_en => pgm_en
134 | );
135 |
136 | addDec: AddressDecoder port map(
137 | A => ADD_HIGH,
138 | B => B,
139 | CLK => CLK,
140 | PHI0 => PHI0,
141 | RNW => RNW,
142 | NDEV_SEL => NDEV_SEL,
143 | NIO_SEL => NIO_SEL,
144 | NIO_STB => NIO_STB,
145 | NRESET => NRESET,
146 | DATA_EN => data_en,
147 | PGM_EN => pgm_en,
148 | NOE => NOE,
149 | NWE => NWE,
150 | NG => NG
151 | );
152 |
153 | DATA <= data_out when (data_en = '1') else (others => 'Z'); -- data bus tristate
154 |
155 | -- synthesis translate_off
156 | data_dbg <= data_in;
157 | add_dbg <= addr_low_int;
158 | data_en_dbg <= data_en;
159 | -- synthesis translate_on
160 |
161 | data_latch: process(CLK)
162 | begin
163 | if falling_edge(CLK) then
164 | addr_low_int <= ADD_LOW;
165 | if (NDEV_SEL = '0') then
166 | data_in <= DATA;
167 | end if;
168 | end if;
169 | end process;
170 |
171 | end Behavioral;
172 |
173 |
--------------------------------------------------------------------------------
/VHDL/AppleIISd_PC44.ucf:
--------------------------------------------------------------------------------
1 | #PACE: Start of Constraints generated by PACE
2 |
3 | #PACE: Start of PACE I/O Pin Assignments
4 | NET "ADD_HIGH<10>" LOC = "P38" ;
5 | NET "ADD_HIGH<11>" LOC = "P44" ;
6 | NET "ADD_HIGH<8>" LOC = "P36" ;
7 | NET "ADD_HIGH<9>" LOC = "P37" ;
8 | NET "ADD_LOW<0>" LOC = "P19" ;
9 | NET "ADD_LOW<1>" LOC = "P18" ;
10 | NET "B<10>" LOC = "P22" ;
11 | NET "B<8>" LOC = "P26" ;
12 | NET "B<9>" LOC = "P27" ;
13 | NET "CARD" LOC = "P33" ;
14 | NET "CLK" LOC = "P43" ;
15 | NET "DATA<0>" LOC = "P3" ;
16 | NET "DATA<1>" LOC = "P4" ;
17 | NET "DATA<2>" LOC = "P5" | BUFG = DATA_GATE ;
18 | NET "DATA<3>" LOC = "P6" | BUFG = DATA_GATE ;
19 | NET "DATA<4>" LOC = "P7" | BUFG = DATA_GATE ;
20 | NET "DATA<5>" LOC = "P9" ;
21 | NET "DATA<6>" LOC = "P11" ;
22 | NET "DATA<7>" LOC = "P13" ;
23 | NET "LED" LOC = "P29" ;
24 | NET "MISO" LOC = "P40" ;
25 | NET "MOSI" LOC = "P35" ;
26 | NET "NDEV_SEL" LOC = "P24" ;
27 | NET "NG" LOC = "P12" ;
28 | NET "NIO_SEL" LOC = "P14" ;
29 | NET "NIO_STB" LOC = "P42" ;
30 | NET "NOE" LOC = "P25" ;
31 | NET "NRESET" LOC = "P20" ;
32 | NET "NSEL" LOC = "P28" ;
33 | NET "NWE" LOC = "P2" ;
34 | NET "PHI0" LOC = "P8" ;
35 | NET "RNW" LOC = "P1" ;
36 | NET "SCLK" LOC = "P34" ;
37 | NET "WP" LOC = "P39" ;
38 |
39 | #PACE: Start of PACE Area Constraints
40 |
41 | #PACE: Start of PACE Prohibit Constraints
42 |
43 | #PACE: End of Constraints generated by PACE
44 |
--------------------------------------------------------------------------------
/VHDL/AppleIISd_PC44.xise:
--------------------------------------------------------------------------------
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 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
--------------------------------------------------------------------------------
/VHDL/AppleIISd_Test.vhd:
--------------------------------------------------------------------------------
1 | --------------------------------------------------------------------------------
2 | -- Company:
3 | -- Engineer:
4 | --
5 | -- Create Date: 00:42:59 10/10/2017
6 | -- Design Name:
7 | -- Module Name: U:/AppleIISd/VHDL/IO_Test.vhd
8 | -- Project Name: AppleIISd
9 | -- Target Device:
10 | -- Tool versions:
11 | -- Description:
12 | --
13 | -- VHDL Test Bench Created by ISE for module: IO
14 | --
15 | -- Dependencies:
16 | --
17 | -- Revision:
18 | -- Revision 0.01 - File Created
19 | -- Additional Comments:
20 | --
21 | -- Notes:
22 | -- This testbench has been automatically generated using types std_logic and
23 | -- std_logic_vector for the ports of the unit under test. Xilinx recommends
24 | -- that these types always be used for the top-level I/O of a design in order
25 | -- to guarantee that the testbench will bind correctly to the post-implementation
26 | -- simulation model.
27 | --------------------------------------------------------------------------------
28 | LIBRARY ieee;
29 | USE ieee.std_logic_1164.ALL;
30 |
31 | -- Uncomment the following library declaration if using
32 | -- arithmetic functions with Signed or Unsigned values
33 | --USE ieee.numeric_std.ALL;
34 |
35 | ENTITY AppleIISd_Test IS
36 | END AppleIISd_Test;
37 |
38 | ARCHITECTURE behavior OF AppleIISd_Test IS
39 |
40 | -- Component Declaration for the Unit Under Test (UUT)
41 |
42 | COMPONENT AppleIISd
43 | PORT(
44 | ADD_HIGH : IN std_logic_vector(11 downto 8);
45 | ADD_LOW : IN std_logic_vector(1 downto 0);
46 | B : OUT std_logic_vector(10 downto 8);
47 | CARD : IN std_logic;
48 | DATA : INOUT std_logic_vector(7 downto 0);
49 | CLK : IN std_logic;
50 | LED : OUT std_logic;
51 | NDEV_SEL : IN std_logic;
52 | NG : OUT std_logic;
53 | NIO_SEL : IN std_logic;
54 | NIO_STB : IN std_logic;
55 | NOE : OUT std_logic;
56 | PHI0 : IN std_logic;
57 | NRESET : IN std_logic;
58 | RNW : IN std_logic;
59 | MISO : IN std_logic;
60 | MOSI : OUT std_logic;
61 | NSEL : OUT std_logic;
62 | SCLK : OUT std_logic;
63 | WP : IN std_logic;
64 |
65 | data_dbg : out std_logic_vector (7 downto 0);
66 | add_dbg : out std_logic_vector (1 downto 0);
67 | data_en_dbg : out std_logic
68 | );
69 | END COMPONENT;
70 |
71 |
72 | --Inputs
73 | signal ADD_HIGH : std_logic_vector(11 downto 8) := (others => '0');
74 | signal ADD_LOW : std_logic_vector(1 downto 0) := (others => 'U');
75 | signal CARD : std_logic := '0';
76 | signal CLK : std_logic := '0';
77 | signal NDEV_SEL : std_logic := '1';
78 | signal NIO_SEL : std_logic := '1';
79 | signal NIO_STB : std_logic := '1';
80 | signal PHI0 : std_logic := '1';
81 | signal NRESET : std_logic := '1';
82 | signal RNW : std_logic := '1';
83 | signal MISO : std_logic := '1';
84 | signal WP : std_logic := '0';
85 |
86 | --BiDirs
87 | signal DATA : std_logic_vector(7 downto 0) := (others => 'Z');
88 |
89 | --Outputs
90 | signal B : std_logic_vector(10 downto 8);
91 | signal LED : std_logic;
92 | signal NG : std_logic;
93 | signal NOE : std_logic;
94 | signal MOSI : std_logic;
95 | signal NSEL : std_logic;
96 | signal SCLK : std_logic;
97 |
98 | signal data_dbg : std_logic_vector (7 downto 0);
99 | signal add_dbg : std_logic_vector (1 downto 0);
100 | signal data_en_dbg : std_logic;
101 |
102 | -- Clock period definitions
103 | constant CLK_period : time := 142 ns;
104 |
105 | -- Bus timings
106 | -- worst case
107 | constant ADD_valid : time := 300 ns; -- II+
108 | constant DATA_valid : time := 200 ns; -- II+
109 | constant ADD_hold : time := 15 ns; -- IIgs
110 | --best case
111 | --constant ADD_valid : time := 100 ns; -- IIgs
112 | --constant DATA_valid : time := 30 ns; -- IIgs
113 | --constant ADD_hold : time := 15 ns; -- IIgs
114 |
115 | BEGIN
116 |
117 | -- Instantiate the Unit Under Test (UUT)
118 | uut: AppleIISd PORT MAP (
119 | ADD_HIGH => ADD_HIGH,
120 | ADD_LOW => ADD_LOW,
121 | B => B,
122 | CARD => CARD,
123 | DATA => DATA,
124 | CLK => CLK,
125 | LED => LED,
126 | NDEV_SEL => NDEV_SEL,
127 | NG => NG,
128 | NIO_SEL => NIO_SEL,
129 | NIO_STB => NIO_STB,
130 | NOE => NOE,
131 | PHI0 => PHI0,
132 | NRESET => NRESET,
133 | RNW => RNW,
134 | MISO => MISO,
135 | MOSI => MOSI,
136 | NSEL => NSEL,
137 | SCLK => SCLK,
138 | WP => WP,
139 |
140 | data_dbg => data_dbg,
141 | add_dbg => add_dbg,
142 | data_en_dbg => data_en_dbg
143 | );
144 |
145 | -- Clock process definitions
146 | CLK_process :process
147 | begin
148 | CLK <= '0';
149 | wait for CLK_period/2;
150 | CLK <= '1';
151 | wait for CLK_period/2;
152 | end process;
153 |
154 | PHI0_process :process(CLK)
155 | variable counter : integer range 0 to 7;
156 | begin
157 | if rising_edge(CLK) or falling_edge(CLK) then
158 | counter := counter + 1;
159 | if counter = 7 then
160 | PHI0 <= not PHI0;
161 | counter := 0;
162 | end if;
163 | end if;
164 | end process;
165 |
166 |
167 | -- Stimulus process
168 | stim_proc: process
169 | begin
170 | -- hold reset state.
171 | wait for CLK_period * 10;
172 | NRESET <= '0';
173 | wait for CLK_period * 20;
174 | NRESET <= '1';
175 | wait for CLK_period * 10;
176 | DATA <= (others => 'Z');
177 | ADD_LOW <= (others => 'U');
178 |
179 | -- read reg 3
180 | wait until falling_edge(PHI0);
181 | wait for ADD_valid;
182 | ADD_LOW <= (others => '1');
183 | RNW <= '1';
184 | DATA <= (others => 'U');
185 | wait until rising_edge(PHI0);
186 | NDEV_SEL <= '0';
187 | DATA <= (others => 'Z');
188 | wait until falling_edge(PHI0);
189 | NDEV_SEL <= '1';
190 | wait for ADD_hold;
191 | ADD_LOW <= (others => 'U');
192 |
193 | -- select card
194 | wait until falling_edge(PHI0);
195 | wait for ADD_valid;
196 | ADD_LOW <= (others => '1');
197 | RNW <= '0';
198 | DATA <= (others => 'U');
199 | wait until rising_edge(PHI0);
200 | NDEV_SEL <= '0';
201 | DATA <= (others => 'Z');
202 | wait for DATA_valid;
203 | DATA <= X"00";
204 | wait until falling_edge(PHI0);
205 | NDEV_SEL <= '1';
206 | wait for ADD_hold;
207 | --wait for CLK_period;
208 | ADD_LOW <= (others => 'U');
209 | RNW <= '1';
210 | DATA <= (others => 'Z');
211 |
212 | -- send data
213 | wait until falling_edge(PHI0);
214 | wait for ADD_valid;
215 | ADD_LOW <= (others => '0');
216 | RNW <= '0';
217 | DATA <= (others => 'U');
218 | wait until rising_edge(PHI0);
219 | NDEV_SEL <= '0';
220 | DATA <= (others => 'Z');
221 | wait for DATA_valid;
222 | DATA <= X"AA";
223 | wait until falling_edge(PHI0);
224 | NDEV_SEL <= '1';
225 | wait for ADD_hold;
226 | --wait for CLK_period;
227 | ADD_LOW <= (others => 'U');
228 | RNW <= '1';
229 | DATA <= (others => 'Z');
230 | wait for 20 us;
231 |
232 | -- deselect card
233 | wait until falling_edge(PHI0);
234 | wait for ADD_valid;
235 | ADD_LOW <= (others => '1');
236 | RNW <= '0';
237 | DATA <= (others => 'U');
238 | wait until rising_edge(PHI0);
239 | NDEV_SEL <= '0';
240 | DATA <= (others => 'Z');
241 | wait for DATA_valid;
242 | DATA <= X"01";
243 | wait until falling_edge(PHI0);
244 | NDEV_SEL <= '1';
245 | wait for ADD_hold;
246 | --wait for CLK_period;
247 | ADD_LOW <= (others => 'U');
248 | RNW <= '1';
249 | DATA <= (others => 'Z');
250 |
251 | -- write ece
252 | wait until falling_edge(PHI0);
253 | wait for ADD_valid;
254 | ADD_LOW <= "01";
255 | RNW <= '0';
256 | DATA <= (others => 'U');
257 | wait until rising_edge(PHI0);
258 | NDEV_SEL <= '0';
259 | DATA <= (others => 'Z');
260 | wait for DATA_valid;
261 | DATA <= x"04";
262 | wait until falling_edge(PHI0);
263 | NDEV_SEL <= '1';
264 | wait for ADD_hold;
265 | --wait for CLK_period;
266 | ADD_LOW <= (others => 'U');
267 | RNW <= '1';
268 | DATA <= (others => 'Z');
269 |
270 | -- send data
271 | wait until falling_edge(PHI0);
272 | wait for ADD_valid;
273 | ADD_LOW <= (others => '0');
274 | RNW <= '0';
275 | DATA <= (others => 'U');
276 | wait until rising_edge(PHI0);
277 | NDEV_SEL <= '0';
278 | DATA <= (others => 'Z');
279 | wait for DATA_valid;
280 | DATA <= X"AA";
281 | wait until falling_edge(PHI0);
282 | NDEV_SEL <= '1';
283 | wait for ADD_hold;
284 | --wait for CLK_period;
285 | ADD_LOW <= (others => 'U');
286 | RNW <= '1';
287 | DATA <= (others => 'Z');
288 |
289 | -- read eprom low
290 | wait for 3 us;
291 | wait until falling_edge(PHI0);
292 | wait for ADD_valid;
293 | ADD_LOW <= (others => '0');
294 | ADD_HIGH <= "0100"; -- must become "111"
295 | RNW <= '1';
296 | DATA <= (others => 'U');
297 | wait until rising_edge(PHI0);
298 | NIO_SEL <= '0';
299 | DATA <= (others => 'Z');
300 | wait until falling_edge(PHI0);
301 | NIO_SEL <= '1';
302 | wait for ADD_hold;
303 | ADD_LOW <= (others => 'U');
304 | ADD_HIGH <= (others => 'U');
305 |
306 | -- read eprom high, selected
307 | wait until falling_edge(PHI0);
308 | wait for ADD_valid;
309 | ADD_LOW <= (others => '0');
310 | ADD_HIGH <= "1001"; -- must become "001"
311 | RNW <= '1';
312 | DATA <= (others => 'U');
313 | wait until rising_edge(PHI0);
314 | NIO_STB <= '0';
315 | DATA <= (others => 'Z');
316 | wait until falling_edge(PHI0);
317 | NIO_STB <= '1';
318 | wait for ADD_hold;
319 | ADD_LOW <= (others => 'U');
320 | ADD_HIGH <= (others => 'U');
321 |
322 | -- read $CFFF
323 | wait until falling_edge(PHI0);
324 | wait for ADD_valid;
325 | ADD_LOW <= (others => '1');
326 | ADD_HIGH <= "1111";
327 | RNW <= '1';
328 | DATA <= (others => 'U');
329 | wait until rising_edge(PHI0);
330 | NIO_STB <= '0';
331 | DATA <= (others => 'Z');
332 | wait until falling_edge(PHI0);
333 | NIO_STB <= '1';
334 | wait for ADD_hold;
335 | ADD_LOW <= (others => 'U');
336 | ADD_HIGH <= (others => 'U');
337 |
338 | -- read eprom high, deselected
339 | wait until falling_edge(PHI0);
340 | wait for ADD_valid;
341 | ADD_LOW <= (others => '0');
342 | ADD_HIGH <= "1101"; -- must become "101"
343 | RNW <= '1';
344 | DATA <= (others => 'U');
345 | wait until rising_edge(PHI0);
346 | NIO_STB <= '0';
347 | DATA <= (others => 'Z');
348 | wait until falling_edge(PHI0);
349 | NIO_STB <= '1';
350 | wait for ADD_hold;
351 | ADD_LOW <= (others => 'U');
352 | ADD_HIGH <= (others => 'U');
353 |
354 | wait;
355 | end process;
356 |
357 | END;
358 |
--------------------------------------------------------------------------------
/VHDL/AppleIISd_VQ44.ucf:
--------------------------------------------------------------------------------
1 | #PACE: Start of Constraints generated by PACE
2 |
3 | #PACE: Start of PACE I/O Pin Assignments
4 | NET "ADD_HIGH<10>" LOC = "P32" ;
5 | NET "ADD_HIGH<11>" LOC = "P38" ;
6 | NET "ADD_HIGH<8>" LOC = "P30" ;
7 | NET "ADD_HIGH<9>" LOC = "P31" ;
8 | NET "ADD_LOW<0>" LOC = "P13" ;
9 | NET "ADD_LOW<1>" LOC = "P12" ;
10 | NET "B<10>" LOC = "P16" ;
11 | NET "B<8>" LOC = "P20" ;
12 | NET "B<9>" LOC = "P21" ;
13 | NET "CARD" LOC = "P27" ;
14 | NET "CLK" LOC = "P37" ;
15 | NET "DATA<0>" LOC = "P41" ;
16 | NET "DATA<1>" LOC = "P42" ;
17 | NET "DATA<2>" LOC = "P43" ;
18 | NET "DATA<3>" LOC = "P44" ;
19 | NET "DATA<4>" LOC = "P1" ;
20 | NET "DATA<5>" LOC = "P3" ;
21 | NET "DATA<6>" LOC = "P5" ;
22 | NET "DATA<7>" LOC = "P7" ;
23 | NET "LED" LOC = "P23" ;
24 | NET "MISO" LOC = "P34" ;
25 | NET "MOSI" LOC = "P29" ;
26 | NET "NDEV_SEL" LOC = "P18" ;
27 | NET "NG" LOC = "P6" ;
28 | NET "NIO_SEL" LOC = "P8" ;
29 | NET "NIO_STB" LOC = "P36" ;
30 | NET "NOE" LOC = "P19" ;
31 | NET "NRESET" LOC = "P14" ;
32 | NET "NSEL" LOC = "P22" ;
33 | NET "NWE" LOC = "P40" ;
34 | NET "PHI0" LOC = "P2" ;
35 | NET "RNW" LOC = "P39" ;
36 | NET "SCLK" LOC = "P28" ;
37 | NET "WP" LOC = "P33" ;
38 |
39 | #PACE: Start of PACE Area Constraints
40 |
41 | #PACE: Start of PACE Prohibit Constraints
42 |
43 | #PACE: End of Constraints generated by PACE
44 |
--------------------------------------------------------------------------------
/VHDL/SpiController.vhd:
--------------------------------------------------------------------------------
1 | ----------------------------------------------------------------------------------
2 | --
3 | -- Spi controller for 6502 systems
4 | -- based on a design by A. Fachat
5 | --
6 | ----------------------------------------------------------------------------------
7 | library IEEE;
8 | use IEEE.STD_LOGIC_1164.ALL;
9 | use IEEE.STD_LOGIC_UNSIGNED.ALL;
10 |
11 |
12 | entity SpiController is
13 | Port (
14 | data_in : in STD_LOGIC_VECTOR (7 downto 0);
15 | data_out : out STD_LOGIC_VECTOR (7 downto 0);
16 | is_read : in STD_LOGIC;
17 | nreset : in STD_LOGIC;
18 | addr : in STD_LOGIC_VECTOR (1 downto 0);
19 | phi0 : in STD_LOGIC;
20 | ndev_sel : in STD_LOGIC;
21 | clk : in STD_LOGIC;
22 | miso: in std_logic;
23 | mosi : out STD_LOGIC;
24 | sclk : out STD_LOGIC;
25 | nsel : out STD_LOGIC;
26 | wp : in STD_LOGIC;
27 | card : in STD_LOGIC;
28 | pgm_en : out STD_LOGIC;
29 | led : out STD_LOGIC
30 | );
31 | end SpiController;
32 |
33 | architecture Behavioral of SpiController is
34 |
35 | --------------------------
36 | -- internal state
37 | signal spidatain: std_logic_vector (7 downto 0);
38 | signal spidataout: std_logic_vector (7 downto 0);
39 | signal sdhc: std_logic; -- is SDHC card
40 | signal inited: std_logic; -- card initialized
41 | signal pgmen: std_logic; -- enable EEPROM programming
42 |
43 | -- spi register flags
44 | signal tc: std_logic; -- transmission complete; cleared on spi data read
45 | signal bsy: std_logic; -- SPI busy
46 | signal frx: std_logic; -- fast receive mode
47 | signal ece: std_logic; -- external clock enable; 0=phi2, 1=external clock
48 |
49 | signal slavesel: std_logic := '1'; -- slave select output (0=selected)
50 | signal int_miso: std_logic;
51 | --------------------------
52 | -- helper signals
53 |
54 | -- shift engine
55 | signal start_shifting: std_logic := '0'; -- shifting data
56 | signal shifting2: std_logic := '0'; -- shifting data
57 | signal shiftdone: std_logic; -- shifting data done
58 | signal shiftcnt: std_logic_vector(3 downto 0); -- shift counter (5 bit)
59 |
60 | -- spi clock
61 | signal clksrc: std_logic; -- clock source (phi2 or clk_7m)
62 | signal shiftclk : std_logic;
63 |
64 | begin
65 | led <= not (bsy or not slavesel);
66 | bsy <= start_shifting or shifting2;
67 |
68 | process(start_shifting, shiftdone, shiftclk)
69 | begin
70 | if (rising_edge(shiftclk)) then
71 | if (shiftdone = '1') then
72 | shifting2 <= '0';
73 | else
74 | shifting2 <= start_shifting;
75 | end if;
76 | end if;
77 | end process;
78 |
79 | process(shiftcnt, nreset, shiftclk)
80 | begin
81 | if (nreset = '0') then
82 | shiftdone <= '0';
83 | elsif (rising_edge(shiftclk)) then
84 | if (shiftcnt = "1111") then
85 | shiftdone <= '1';
86 | else
87 | shiftdone <= '0';
88 | end if;
89 | end if;
90 | end process;
91 |
92 | process(nreset, shifting2, shiftcnt, shiftclk)
93 | begin
94 | if (nreset = '0') then
95 | shiftcnt <= (others => '0');
96 | elsif (rising_edge(shiftclk)) then
97 | if (shifting2 = '1') then
98 | -- count phase
99 | shiftcnt <= shiftcnt + 1;
100 | else
101 | shiftcnt <= (others => '0');
102 | end if;
103 | end if;
104 | end process;
105 |
106 | inproc: process(nreset, shifting2, shiftcnt, shiftclk, spidatain, miso)
107 | begin
108 | if (nreset = '0') then
109 | spidatain <= (others => '0');
110 | elsif (rising_edge(shiftclk)) then
111 | if (shifting2 = '1' and shiftcnt(0) = '1') then
112 | -- shift in to input register
113 | spidatain (7 downto 1) <= spidatain (6 downto 0);
114 | spidatain (0) <= int_miso;
115 | end if;
116 | end if;
117 | end process;
118 |
119 | outproc: process(nreset, shifting2, spidataout, shiftcnt, shiftclk)
120 | begin
121 | if (nreset = '0') then
122 | mosi <= '1';
123 | sclk <= '1';
124 | else
125 | -- clock is sync'd
126 | if (rising_edge(shiftclk)) then
127 | if (shifting2='0' or shiftdone = '1') then
128 | mosi <= '1';
129 | sclk <= '1';
130 | else
131 | -- output data directly from output register
132 | case shiftcnt(3 downto 1) is
133 | when "000" => mosi <= spidataout(7);
134 | when "001" => mosi <= spidataout(6);
135 | when "010" => mosi <= spidataout(5);
136 | when "011" => mosi <= spidataout(4);
137 | when "100" => mosi <= spidataout(3);
138 | when "101" => mosi <= spidataout(2);
139 | when "110" => mosi <= spidataout(1);
140 | when "111" => mosi <= spidataout(0);
141 | when others => mosi <= '1';
142 | end case;
143 | sclk <= shiftcnt(0);
144 | end if;
145 | end if;
146 | end if;
147 | end process;
148 |
149 |
150 | -- shift operation enable
151 | shiften: process(nreset, ndev_sel, is_read, addr, frx, shiftdone)
152 | begin
153 | -- start shifting
154 | if (nreset = '0' or shiftdone = '1') then
155 | start_shifting <= '0';
156 | elsif (rising_edge(ndev_sel) and addr="00" and (frx='1' or is_read='0')) then
157 | -- access to register 00, either write (is_read=0) or fast receive bit set (frx)
158 | -- then both types of access (write but also read)
159 | start_shifting <= '1';
160 | end if;
161 | end process;
162 |
163 | --------------------------
164 | -- spiclk - spi clock generation
165 | -- spiclk is still 2 times the freq. than sclk
166 | clksrc <= phi0 when (ece = '0') else clk;
167 |
168 | -- is a pulse signal to allow for divisor==0
169 | shiftclk <= clksrc when bsy = '1' else '0';
170 |
171 | --------------------------
172 | -- interface section
173 | -- inputs
174 | int_miso <= (miso and not slavesel);
175 |
176 | -- outputs
177 | nsel <= slavesel;
178 | pgm_en <= pgmen;
179 |
180 | tc_proc: process (ndev_sel, shiftdone)
181 | begin
182 | if (shiftdone = '1') then
183 | tc <= '1';
184 | elsif (rising_edge(ndev_sel) and addr="00") then
185 | tc <= '0';
186 | end if;
187 | end process;
188 |
189 | --------------------------
190 | -- cpu register section
191 | -- cpu read
192 | cpu_read: process(addr, spidatain, tc, bsy, frx, pgmen,
193 | ece, slavesel, wp, card, sdhc, inited)
194 | begin
195 | case addr is
196 | when "00" => -- read SPI data in
197 | data_out <= spidatain;
198 | when "01" => -- read status register
199 | data_out(0) <= pgmen;
200 | data_out(1) <= '0';
201 | data_out(2) <= ece;
202 | data_out(3) <= '0';
203 | data_out(4) <= frx;
204 | data_out(5) <= bsy;
205 | data_out(6) <= '0';
206 | data_out(7) <= tc;
207 | -- no register 2
208 | when "11" => -- read slave select / slave interrupt state
209 | data_out(0) <= slavesel;
210 | data_out(3 downto 1) <= (others => '0');
211 | data_out(4) <= sdhc;
212 | data_out(5) <= wp;
213 | data_out(6) <= card;
214 | data_out(7) <= inited;
215 | when others =>
216 | data_out <= (others => '0');
217 | end case;
218 | end process;
219 |
220 | -- cpu write
221 | cpu_write: process(nreset, ndev_sel, is_read, addr, data_in, card)
222 | begin
223 | if (nreset = '0') then
224 | ece <= '0';
225 | frx <= '0';
226 | slavesel <= '1';
227 | spidataout <= (others => '1');
228 | sdhc <= '0';
229 | inited <= '0';
230 | pgmen <= '0';
231 | elsif (card = '1') then
232 | sdhc <= '0';
233 | inited <= '0';
234 | elsif (rising_edge(ndev_sel) and is_read = '0') then
235 | case addr is
236 | when "00" => -- write SPI data out (see other process above)
237 | spidataout <= data_in;
238 | when "01" => -- write status register
239 | pgmen <= data_in(0);
240 | ece <= data_in(2);
241 | frx <= data_in(4);
242 | -- no bit 5 - 7
243 | -- no register 2
244 | when "11" => -- write slave select
245 | slavesel <= data_in(0);
246 | -- no bit 1 - 3
247 | sdhc <= data_in(4);
248 | -- no bit 5 - 6
249 | inited <= data_in(7);
250 | when others =>
251 | end case;
252 | end if;
253 | end process;
254 |
255 | end Behavioral;
256 |
--------------------------------------------------------------------------------