OpenCores
URL https://opencores.org/ocsvn/s80186/s80186/trunk

Subversion Repositories s80186

[/] [s80186/] [trunk/] [bios/] [disk.c] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 jamieiles
// Copyright Jamie Iles, 2017
2
//
3
// This file is part of s80x86.
4
//
5
// s80x86 is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
//
10
// s80x86 is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
//
15
// You should have received a copy of the GNU General Public License
16
// along with s80x86.  If not, see <http://www.gnu.org/licenses/>.
17
 
18
#include "bios.h"
19
#include "sd.h"
20
#include "io.h"
21
#include "leds.h"
22
#include "serial.h"
23
#include "utils.h"
24
 
25
#define SECTORS_PER_TRACK 63
26
#define NUM_HEADS 16
27
#define NUM_CYLINDERS 4
28
#define SECTOR_SIZE 512
29
 
30
#define FLOPPY_TIMEOUT 0x80
31
 
32
static void set_disk_status(struct callregs *regs, unsigned char err)
33
{
34
    if (err)
35
        regs->flags |= CF;
36
    else
37
        regs->flags &= ~CF;
38
    bda_write(diskette_status, err);
39
    regs->ax.h = err;
40
}
41
 
42
static void disk_read(struct callregs *regs)
43
{
44
    if (regs->dx.l != 0x80) {
45
        set_disk_status(regs, FLOPPY_TIMEOUT);
46
        return;
47
    }
48
 
49
    unsigned short cylinder =
50
        regs->cx.h | (((unsigned short)regs->cx.l & 0xc0) << 2);
51
    unsigned short head = regs->dx.h;
52
    unsigned short sector = regs->cx.l & 0x3f;
53
    unsigned short lba =
54
        (cylinder * NUM_HEADS + head) * SECTORS_PER_TRACK + (sector - 1);
55
    unsigned short i;
56
    unsigned short dst = regs->bx.x;
57
    unsigned short count = regs->ax.l;
58
 
59
    regs->ax.l = 0;
60
    regs->flags &= ~CF;
61
 
62
    for (i = 0; i < count; ++i) {
63
        read_sector(lba, get_es(), dst);
64
        ++lba;
65
        dst += SECTOR_SIZE;
66
        ++regs->ax.l;
67
    }
68
 
69
    set_disk_status(regs, regs->ax.l != count ? 0xff : 0x00);
70
}
71
 
72
static void disk_write(struct callregs *regs)
73
{
74
    if (regs->dx.l != 0x80) {
75
        set_disk_status(regs, FLOPPY_TIMEOUT);
76
        return;
77
    }
78
 
79
    unsigned short cylinder =
80
        regs->cx.h | (((unsigned short)regs->cx.l & 0xc0) << 2);
81
    unsigned short head = regs->dx.h;
82
    unsigned short sector = regs->cx.l & 0x3f;
83
    unsigned short lba =
84
        (cylinder * NUM_HEADS + head) * SECTORS_PER_TRACK + (sector - 1);
85
    unsigned short i;
86
    unsigned short dst = regs->bx.x;
87
    unsigned short count = regs->ax.l;
88
 
89
    regs->ax.l = 0;
90
    regs->flags &= ~CF;
91
 
92
    for (i = 0; i < count; ++i) {
93
        if (write_sector(lba, get_es(), dst)) {
94
            regs->flags |= CF;
95
            break;
96
        }
97
        ++lba;
98
        dst += SECTOR_SIZE;
99
        ++regs->ax.l;
100
    }
101
 
102
    set_disk_status(regs, regs->ax.l != count ? 0xff : 0x00);
103
}
104
 
105
static void disk_status(struct callregs *regs)
106
{
107
    if (regs->dx.l != 0x80) {
108
        set_disk_status(regs, FLOPPY_TIMEOUT);
109
        return;
110
    }
111
 
112
    unsigned char v = bda_read(diskette_status);
113
    bda_write(diskette_status, v);
114
}
115
 
116
static void disk_reset(struct callregs *regs)
117
{
118
    regs->flags &= ~CF;
119
    if (regs->dx.l != 0x80) {
120
        set_disk_status(regs, FLOPPY_TIMEOUT);
121
        return;
122
    }
123
    set_disk_status(regs, 0);
124
}
125
 
126
static void disk_parameters(struct callregs *regs)
127
{
128
    regs->flags &= ~CF;
129
    if (regs->dx.l != 0x80) {
130
        regs->flags |= CF;
131
        set_disk_status(regs, FLOPPY_TIMEOUT);
132
        return;
133
    }
134
 
135
    regs->dx.l = 1; // 1 drive
136
    regs->dx.h = NUM_HEADS - 1;
137
    regs->cx.x = SECTORS_PER_TRACK | (NUM_CYLINDERS << 8);
138
    regs->bx.l = 0;
139
 
140
    set_disk_status(regs, 0);
141
}
142
 
143
static void disk_get_type(struct callregs *regs)
144
{
145
    regs->flags &= ~CF;
146
    if (regs->dx.l != 0x80) {
147
        set_disk_status(regs, FLOPPY_TIMEOUT);
148
        return;
149
    }
150
 
151
    regs->ax.h = 3;
152
    regs->cx.x = regs->dx.x = 0xffff;
153
}
154
 
155
static void disk_services(struct callregs *regs)
156
{
157
    regs->flags |= CF;
158
 
159
    led_set(LED_DISK);
160
    switch (regs->ax.h) {
161
    case 0x00: disk_reset(regs); break;
162
    case 0x01: disk_status(regs); break;
163
    case 0x02: disk_read(regs); break;
164
    case 0x03: disk_write(regs); break;
165
    case 0x08: disk_parameters(regs); break;
166
    case 0x15: disk_get_type(regs); break;
167
    }
168
    led_clear(LED_DISK);
169
}
170
VECTOR(0x13, disk_services);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.