-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcpm_bios.asm
More file actions
268 lines (234 loc) · 10.7 KB
/
cpm_bios.asm
File metadata and controls
268 lines (234 loc) · 10.7 KB
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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
; CP/M 2.2 Compatible BIOS for Core8080 Emulator
; Minimal BIOS that interfaces with C emulator functions
;
; Memory layout:
; 0x0000-0x00FF: System vectors and page zero
; 0x0100-0xDBFF: TPA (Transient Program Area)
; 0xDC00-0xE3FF: CCP (Console Command Processor) - 2KB
; 0xE400-0xF9FF: BDOS (Basic Disk Operating System) - 5.5KB
; 0xFA00-0xFFFF: BIOS (Basic I/O System) - 1.5KB
; BIOS entry point is 0xFA00
ORG 0FA00h
; BIOS Jump Table - Standard CP/M 2.2 Interface
BOOT: JMP BOOT_IMPL ; Cold start
WBOOT: JMP WBOOT_IMPL ; Warm start
CONST: JMP CONST_IMPL ; Console status
CONIN: JMP CONIN_IMPL ; Console input
CONOUT: JMP CONOUT_IMPL ; Console output
LIST: JMP LIST_IMPL ; List output (printer)
PUNCH: JMP PUNCH_IMPL ; Punch output (paper tape)
READER: JMP READER_IMPL ; Reader input (paper tape)
HOME: JMP HOME_IMPL ; Home disk head
SELDSK: JMP SELDSK_IMPL ; Select disk drive
SETTRK: JMP SETTRK_IMPL ; Set track number
SETSEC: JMP SETSEC_IMPL ; Set sector number
SETDMA: JMP SETDMA_IMPL ; Set DMA address
READ: JMP READ_IMPL ; Read disk sector
WRITE: JMP WRITE_IMPL ; Write disk sector
LISTST: JMP LISTST_IMPL ; List status
SECTRAN: JMP SECTRAN_IMPL ; Sector translate
; =============================================================================
; BIOS Implementation
; Each function uses I/O ports to communicate with C emulator
; =============================================================================
; Port definitions for emulator interface
CONST_PORT EQU 0F0h ; Console status port
CONIN_PORT EQU 0F1h ; Console input port
CONOUT_PORT EQU 0F2h ; Console output port
DISK_SELECT EQU 0F3h ; Disk select port
DISK_TRACK EQU 0F4h ; Track number port
DISK_SECTOR EQU 0F5h ; Sector number port
DISK_DMA_LO EQU 0F6h ; DMA address low byte
DISK_DMA_HI EQU 0F7h ; DMA address high byte
DISK_READ EQU 0F8h ; Disk read operation
DISK_WRITE EQU 0F9h ; Disk write operation
DISK_HOME EQU 0FAh ; Disk home operation
; -----------------------------------------------------------------------------
; BOOT - Cold start initialization
; -----------------------------------------------------------------------------
BOOT_IMPL:
LXI SP, 0100h ; Set up stack below TPA
MVI A, 0 ; Select disk A:
STA CDISK ; Save current disk
OUT DISK_SELECT ; Tell emulator
; Print sign-on message
LXI D, SIGNON
MVI C, 9 ; BDOS print string
CALL 0005h ; Call BDOS
; Fall through to warm boot
; -----------------------------------------------------------------------------
; WBOOT - Warm start (reload CCP)
; -----------------------------------------------------------------------------
WBOOT_IMPL:
LXI SP, 0100h ; Reset stack
MVI C, 0 ; Select disk A:
CALL SELDSK_IMPL
; In a full CP/M system, we would reload CCP from disk here
; For now, jump to CCP entry point (assuming it's in memory)
JMP 0DC00h ; Jump to CCP
; -----------------------------------------------------------------------------
; CONST - Console status
; Returns: A = 0xFF if character ready, 0x00 if not
; -----------------------------------------------------------------------------
CONST_IMPL:
IN CONST_PORT ; Read status from emulator
RET
; -----------------------------------------------------------------------------
; CONIN - Console input
; Returns: A = character from console
; -----------------------------------------------------------------------------
CONIN_IMPL:
IN CONIN_PORT ; Read character from emulator
ANI 7Fh ; Strip high bit
RET
; -----------------------------------------------------------------------------
; CONOUT - Console output
; Input: C = character to output
; -----------------------------------------------------------------------------
CONOUT_IMPL:
MOV A, C ; Get character
OUT CONOUT_PORT ; Send to emulator
RET
; -----------------------------------------------------------------------------
; LIST - List output (printer)
; Input: C = character to output
; For this emulator, we just ignore it
; -----------------------------------------------------------------------------
LIST_IMPL:
RET
; -----------------------------------------------------------------------------
; LISTST - List status
; Returns: A = 0xFF if printer ready, 0x00 if not
; -----------------------------------------------------------------------------
LISTST_IMPL:
MVI A, 0FFh ; Always ready (fake it)
RET
; -----------------------------------------------------------------------------
; PUNCH - Punch output (paper tape)
; Input: C = character to output
; -----------------------------------------------------------------------------
PUNCH_IMPL:
RET ; Not implemented
; -----------------------------------------------------------------------------
; READER - Reader input (paper tape)
; Returns: A = character
; -----------------------------------------------------------------------------
READER_IMPL:
MVI A, 1Ah ; Return EOF
RET
; -----------------------------------------------------------------------------
; HOME - Move disk head to track 0
; -----------------------------------------------------------------------------
HOME_IMPL:
OUT DISK_HOME ; Tell emulator to home
MVI A, 0
STA CTRACK ; Track 0
RET
; -----------------------------------------------------------------------------
; SELDSK - Select disk drive
; Input: C = disk number (0=A:, 1=B:, etc.)
; Returns: HL = address of disk parameter header, or 0000h if error
; -----------------------------------------------------------------------------
SELDSK_IMPL:
MOV A, C ; Get disk number
CPI 2 ; Check if valid (0-1 for A: and B:)
JNC SELDSK_ERR ; Invalid disk
STA CDISK ; Save current disk
OUT DISK_SELECT ; Tell emulator
; Return DPH address for this disk
; We'll use a simple DPH
LXI H, DPH0 ; Return DPH address
RET
SELDSK_ERR:
LXI H, 0 ; Return error
RET
; -----------------------------------------------------------------------------
; SETTRK - Set track number
; Input: BC = track number
; -----------------------------------------------------------------------------
SETTRK_IMPL:
MOV A, C ; Get track number (only low byte)
STA CTRACK ; Save current track
OUT DISK_TRACK ; Tell emulator
RET
; -----------------------------------------------------------------------------
; SETSEC - Set sector number
; Input: BC = sector number
; -----------------------------------------------------------------------------
SETSEC_IMPL:
MOV A, C ; Get sector number
STA CSECTOR ; Save current sector
OUT DISK_SECTOR ; Tell emulator
RET
; -----------------------------------------------------------------------------
; SETDMA - Set DMA address
; Input: BC = DMA address
; -----------------------------------------------------------------------------
SETDMA_IMPL:
MOV A, C ; Low byte
OUT DISK_DMA_LO
STA CDMA ; Save DMA low
MOV A, B ; High byte
OUT DISK_DMA_HI
STA CDMA+1 ; Save DMA high
RET
; -----------------------------------------------------------------------------
; READ - Read sector
; Returns: A = 0 if OK, 1 if error
; -----------------------------------------------------------------------------
READ_IMPL:
IN DISK_READ ; Trigger read operation
RET ; A contains result from emulator
; -----------------------------------------------------------------------------
; WRITE - Write sector
; Input: C = write type (0=normal, 1=directory, 2=unallocated)
; Returns: A = 0 if OK, 1 if error
; -----------------------------------------------------------------------------
WRITE_IMPL:
IN DISK_WRITE ; Trigger write operation
RET ; A contains result from emulator
; -----------------------------------------------------------------------------
; SECTRAN - Sector translation
; Input: BC = logical sector, DE = translate table address
; Returns: HL = physical sector
; For now, we use identity mapping (no translation)
; -----------------------------------------------------------------------------
SECTRAN_IMPL:
MOV L, C ; Logical sector to HL
MOV H, B
RET
; =============================================================================
; Data Area
; =============================================================================
; Current disk parameters
CDISK: DB 0 ; Current disk (0=A:)
CTRACK: DB 0 ; Current track
CSECTOR: DB 0 ; Current sector
CDMA: DW 0080h ; Current DMA address
; Disk Parameter Header (simplified)
DPH0: DW 0 ; XLT - Sector translation table (none)
DW 0 ; Scratch area
DW 0 ; Scratch area
DW 0 ; Scratch area
DW DIRBUF ; DIR - Directory buffer
DW DPB0 ; DPB - Disk parameter block
DW CSV0 ; CSV - Checksum vector
DW ALV0 ; ALV - Allocation vector
; Disk Parameter Block for standard CP/M 2.2 disk
; 77 tracks, 26 sectors/track, 128 bytes/sector
DPB0: DW 26 ; SPT - Sectors per track
DB 3 ; BSH - Block shift factor
DB 7 ; BLM - Block mask
DB 0 ; EXM - Extent mask
DW 242 ; DSM - Disk size - 1 (in blocks)
DW 63 ; DRM - Directory max - 1
DB 192 ; AL0 - Alloc 0
DB 0 ; AL1 - Alloc 1
DW 16 ; CKS - Check size
DW 2 ; OFF - Track offset
; Buffers and work areas
DIRBUF: DS 128 ; Directory buffer
CSV0: DS 16 ; Checksum vector
ALV0: DS 32 ; Allocation vector
SIGNON: DB 'CP/M 2.2 Core8080 BIOS', 0Dh, 0Ah, '$'
END