Initial Commit
This commit is contained in:
commit
d42e892b45
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
52
.gitignore
vendored
Normal file
52
.gitignore
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Object files
|
||||||
|
*.o
|
||||||
|
*.ko
|
||||||
|
*.obj
|
||||||
|
*.elf
|
||||||
|
|
||||||
|
# Linker output
|
||||||
|
*.ilk
|
||||||
|
*.map
|
||||||
|
*.exp
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Libraries
|
||||||
|
*.lib
|
||||||
|
*.a
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
|
||||||
|
# Shared objects (inc. Windows DLLs)
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
*.i*86
|
||||||
|
*.x86_64
|
||||||
|
*.hex
|
||||||
|
|
||||||
|
# Debug files
|
||||||
|
*.dSYM/
|
||||||
|
*.su
|
||||||
|
*.idb
|
||||||
|
*.pdb
|
||||||
|
|
||||||
|
# Kernel Module Compile Results
|
||||||
|
*.mod*
|
||||||
|
*.cmd
|
||||||
|
.tmp_versions/
|
||||||
|
modules.order
|
||||||
|
Module.symvers
|
||||||
|
Mkfile.old
|
||||||
|
dkms.conf
|
29
LICENSE
Normal file
29
LICENSE
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2021, Peter J. Weingartner
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
74
README.md
Normal file
74
README.md
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
# Foenix Toolbox
|
||||||
|
|
||||||
|
## About This Project
|
||||||
|
|
||||||
|
The Foenix Toolbox is a light-weight firmware package intended for the [Foenix Retro Systems](https://c256foenix.com) retro-style computers. The design purpose of the toolbox is primarily to boot the computer and to provide a library of core routines for various functions that the programmer might find tedious to implement.
|
||||||
|
|
||||||
|
## The Toolbox API
|
||||||
|
|
||||||
|
The API provided by the toolbox is broken out into several sections:
|
||||||
|
|
||||||
|
* Character stream based I/O: keyboard, text screen (ANSI escape support), serial port
|
||||||
|
* Block based storage I/O: SD card
|
||||||
|
* File systems: SD card FAT32 file access, IEC storage device (Commodore DOS access)
|
||||||
|
* Time: Real-time clock access, jiffie-clock counter
|
||||||
|
* Interrupt handler support [TO BE REMOVED?]
|
||||||
|
* Low-level keyboard and text (scan codes, keyboard layout, text mode controls)
|
||||||
|
* System ID
|
||||||
|
* Process routines (start a program or stop it) [TO BE REMOVED?]
|
||||||
|
* Memory routines (reserve memory) [TO BE REMOVED?]
|
||||||
|
* Loading and running binary files on storage (PGX, PGZ, and ELF) [TO BE REMOVED?]
|
||||||
|
|
||||||
|
## Boot Process
|
||||||
|
|
||||||
|
One of the key functions of the toolbox is to initialize the computer at bootup time and to launch a more complete operating system or user program. The system will boot in the following manner:
|
||||||
|
|
||||||
|
|
||||||
|
### Proposed Boot Sequence
|
||||||
|
|
||||||
|
1. Initialize I/O devices (screen, sound devices, *etc.*) to a known, neutral state.
|
||||||
|
2. Display a booting/splash screen
|
||||||
|
3. If the DIP switches are set to allow boot from RAM:
|
||||||
|
1. Scan each 8KB block of RAM for the [program header](progheader.md).
|
||||||
|
2. If one is found, run the program linked.
|
||||||
|
4. If a flash cartridge is inserted:
|
||||||
|
1. Check the first 8KB block of the cartridge for the [program header](progheader.md).
|
||||||
|
2. If one is found, run the program linked.
|
||||||
|
5. If an SD card is inserted:
|
||||||
|
1. Check for an executable boot sector.
|
||||||
|
2. If one is found, execute it.
|
||||||
|
6. Check any internal SD card for an executable boot sector.
|
||||||
|
7. If one is found, execute it.
|
||||||
|
8. Scan each 8KB block of the firmware flash for the [program header](progheader.md).
|
||||||
|
9. If one is found, run the program linked.
|
||||||
|
10. If nothing else is found, wait for an SD card to be inserted and repeat step 4.
|
||||||
|
|
||||||
|
### Machine-specific Calling Conventions
|
||||||
|
|
||||||
|
* [ABI for WDC65C816-based Machines](src/C256/ABI.md)
|
||||||
|
|
||||||
|
## Building the Toolbox
|
||||||
|
|
||||||
|
1. Change your directory to the `src` directory
|
||||||
|
2. Execute `make clean` to ensure any previous build files are removed
|
||||||
|
3. Execute `make UNIT=<...> MEMORY=ROM` to build a binary for a particular Foenix model that can be loaded into the flash memory. Or Execute `make UNIT=<...> MEMORY=RAM` to build a RAM loadable version for testing.
|
||||||
|
|
||||||
|
The following UNIT labels are supported: `C256U`, `C256_FMX`, `F256Ke` for the original F256K with a W65C816 processor and the flat memory model FPGA, or `F256K2e` for the original F256K2 with a W65C816 processor and the flat memory model FPGA.
|
||||||
|
|
||||||
|
NOTE: Foenix Toolbox does not work on any F256 with the W65C02 processor or with the original FPGA load that provides a 64KB address space for the processor. It needs full 24-bit addressing to work.
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
The toolbox project is intended to be compiled using the [Calypsi C compiler](https://www.calypsi.cc/). To build the project, you will need:
|
||||||
|
|
||||||
|
* The correct version of Calypsi for the target system
|
||||||
|
* An implementation of `make` for your build computer
|
||||||
|
* Python3
|
||||||
|
* Some utility for uploading the binary to the Foenix machine (for instance [FoenixMgr](https://github.com/pweingar/FoenixMgr))
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Generally, the code for the Foenix Toolbox is covered under the BSD-3 open source license. The toolbox includes code from other projects, however, and that code is covered under the licenses used by those projects. This code includes:
|
||||||
|
|
||||||
|
* [FatFS](http://elm-chan.org/fsw/ff/), which is used for the FAT32 implementation and is distributed under a BSD-style license. The license and copyright notice for FatFS are included in the source code.
|
||||||
|
|
BIN
misc/F256xE_Kernal_Code.zip
Normal file
BIN
misc/F256xE_Kernal_Code.zip
Normal file
Binary file not shown.
20
progheader.md
Normal file
20
progheader.md
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# Foenix Toolbox Program Header
|
||||||
|
|
||||||
|
To recognize a program or bootable module in RAM or flash, the toolbox needs a small header to identify the program. This header is based on the Kernel User Program headers used by the default kernel for the 8-bit versions of the F256, but it has been modified to conform to the 24-bit memory model of the F256K2e:
|
||||||
|
|
||||||
|
| Byte | Value |
|
||||||
|
| ---- | ----- |
|
||||||
|
| 0 | Signature: $F8 |
|
||||||
|
| 1 | Signature: $16 |
|
||||||
|
| 2 | Size of the program in 8KB blocks |
|
||||||
|
| 3 | Reserved |
|
||||||
|
| 4 -- 5 | Starting address of the program, little-endian format |
|
||||||
|
| 6 | Header structure version number |
|
||||||
|
| 7 -- 9 | Reserved |
|
||||||
|
| 10 -- m | Zero-terminated string: name of the program |
|
||||||
|
| m+1 -- n | Zero-terminated string describing the arguments |
|
||||||
|
| n+1 -- p | Zero-terminated string describing the program's function |
|
||||||
|
|
||||||
|
The header must be present at the beginning of an 8KB block of memory to be recognized. If the option to boot from RAM is present, then this header may be present at the beginning of any 8KB block of memory. If the option is off, headers in RAM will be ignored.
|
||||||
|
|
||||||
|
To boot from the flash cartridge, this header must be the first thing in the cartridge memory. That is, only the first 8KB block of the expansion cartridge will be checked at boot time.
|
13
src/C256/ABI.md
Normal file
13
src/C256/ABI.md
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Foenix Toolbox ABI for 65816 Machines
|
||||||
|
|
||||||
|
Toolbox functions are compiled using Calypsi's `simple_call` convention. In this convention, the first parameter is passed in register, while the remaining parameters are passed on the stack. Results are returned in the A, C, or X:C registers according to the size of the return value. Note that registers C, X, Y, and the direct page pseudo-registers 0 - 7 may be altered by the function.
|
||||||
|
|
||||||
|
| Type | Size | Register |
|
||||||
|
| ---- | ---- | -------- |
|
||||||
|
| char | 8 | A |
|
||||||
|
| int, short, tiny, and near pointers | 16 | C |
|
||||||
|
| long, float, far and huge pointers | 32 | X:C |
|
||||||
|
|
||||||
|
Please see the Calypsi manual for further details about the `simple_call` convention.
|
||||||
|
|
||||||
|
All toolbox functions are available through a jumptable starting at $00:F000 and are far-call subroutines, so the caller must use the `JSL` instruction to call them.
|
37
src/C256/extras.s
Normal file
37
src/C256/extras.s
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
.public restart_cli
|
||||||
|
|
||||||
|
.extern cli_rerepl
|
||||||
|
.extern _Vfp
|
||||||
|
.extern _DirectPageStart
|
||||||
|
|
||||||
|
#ifndef __CALYPSI_DATA_MODEL_SMALL__
|
||||||
|
.extern _NearBaseAddress
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.section stack
|
||||||
|
.section code
|
||||||
|
|
||||||
|
;
|
||||||
|
; Reset the stack to the initial value.
|
||||||
|
; Reset the direct page and data bank registers
|
||||||
|
; Restart the CLI
|
||||||
|
;
|
||||||
|
restart_cli:
|
||||||
|
rep #0x38 ; 16-bit registers, no decimal mode
|
||||||
|
ldx ##.sectionEnd stack
|
||||||
|
txs ; set stack
|
||||||
|
lda ##_DirectPageStart
|
||||||
|
tcd ; set direct page
|
||||||
|
#ifdef __CALYPSI_DATA_MODEL_SMALL__
|
||||||
|
lda ##0
|
||||||
|
#else
|
||||||
|
lda ##.word2 _NearBaseAddress
|
||||||
|
#endif
|
||||||
|
stz dp:.tiny(_Vfp+2)
|
||||||
|
xba ; A upper half = data bank
|
||||||
|
pha
|
||||||
|
plb ; pop 8 dummy
|
||||||
|
plb ; set data bank
|
||||||
|
|
||||||
|
; jsl cli_rerepl
|
||||||
|
bra restart_cli
|
34
src/C256/flash-u-plus.scm
Normal file
34
src/C256/flash-u-plus.scm
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
(define memories
|
||||||
|
'((memory flash (address (#xf80000 . #xffffff)) (fill 0)
|
||||||
|
(section (LoCodeStorage #xf8f000)
|
||||||
|
(VectorStorage #xf8ffe0)
|
||||||
|
(HiCodeStorage1 (#xfd0000 . #xfdffff))
|
||||||
|
(HiCodeStorage2 (#xfe0000 . #xfeffff))
|
||||||
|
(HiCodeStorage3 (#xff0000 . #xffffff))))
|
||||||
|
(memory DirectPage (address (#x00c000 . #x00c0ff))
|
||||||
|
(section (registers ztiny)))
|
||||||
|
(memory LoRAM (address (#x00c100 . #x00efff))
|
||||||
|
(section stack data zdata data heap))
|
||||||
|
(memory NearRAM1 (address (#x010000 . #x017fff))
|
||||||
|
(section znear near))
|
||||||
|
(memory NearRAM2 (address (#x018000 . #x01ffff))
|
||||||
|
(section cnear))
|
||||||
|
(memory FarRAM1 (address (#x020000 . #x02ffff))
|
||||||
|
(section far huge))
|
||||||
|
(memory FarRAM2 (address (#x030000 . #x03ffff))
|
||||||
|
(section zfar zhuge ))
|
||||||
|
(memory LoCode (address (#x00f000 . #x00ffdf)) (scatter-to LoCodeStorage)
|
||||||
|
(section code cdata (jumptable #x00f000)))
|
||||||
|
(memory Vector (address (#x00ffe0 . #x00ffff)) (scatter-to VectorStorage)
|
||||||
|
(section (reset #xfffc)))
|
||||||
|
(memory HiCode1 (address (#x3d0000 . #x3dffff)) (scatter-to HiCodeStorage1)
|
||||||
|
(section cfar switch data_init_table ifar farcode))
|
||||||
|
(memory HiCode2 (address (#x3e0000 . #x3effff)) (scatter-to HiCodeStorage2)
|
||||||
|
(section cfar switch data_init_table ifar farcode))
|
||||||
|
(memory HiCode3 (address (#x3f0000 . #x3fffff)) (scatter-to HiCodeStorage3)
|
||||||
|
(section cfar switch data_init_table ifar farcode))
|
||||||
|
(block stack (size #x1000))
|
||||||
|
(block heap (size #x1000))
|
||||||
|
(base-address _DirectPageStart DirectPage 0)
|
||||||
|
(base-address _NearBaseAddress NearRAM1 0)
|
||||||
|
))
|
53
src/C256/gentables.py
Normal file
53
src/C256/gentables.py
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#
|
||||||
|
# Generate the assembly files for both the system call library and the kernel jump tabls
|
||||||
|
#
|
||||||
|
|
||||||
|
sys_call_names = []
|
||||||
|
|
||||||
|
# Read in the list of system calls ("sys_")
|
||||||
|
with open("syscalls.txt", "r") as call_names:
|
||||||
|
for line in call_names:
|
||||||
|
# Remove comments
|
||||||
|
index = line.find("#")
|
||||||
|
if index == 0:
|
||||||
|
line = ""
|
||||||
|
elif index > 0:
|
||||||
|
line = line[index - 1:]
|
||||||
|
|
||||||
|
line = line.strip()
|
||||||
|
|
||||||
|
# Skip blank lines
|
||||||
|
if len(line) > 0:
|
||||||
|
sys_call_names.append(line)
|
||||||
|
|
||||||
|
# # Create the system call table, which is used to call into the kernel jump table
|
||||||
|
|
||||||
|
# with open("syscalls.s", "w") as f:
|
||||||
|
# for call_name in sys_call_names:
|
||||||
|
# f.write("\t.public sys_{}\n".format(call_name))
|
||||||
|
|
||||||
|
# f.write("\n")
|
||||||
|
|
||||||
|
# for call_name in sys_call_names:
|
||||||
|
# f.write("\t.extern sjt_{}\n".format(call_name))
|
||||||
|
|
||||||
|
# f.write("\n\t.section farcode\n\n");
|
||||||
|
|
||||||
|
# for call_name in sys_call_names:
|
||||||
|
# f.write("sys_{:26}\t.equlab sjt_{}\n".format(call_name + ": ", call_name))
|
||||||
|
|
||||||
|
# Create the kernel jump table
|
||||||
|
|
||||||
|
with open("jumptable.s", "w") as f:
|
||||||
|
for call_name in sys_call_names:
|
||||||
|
f.write("\t.public sys_{}\n".format(call_name))
|
||||||
|
|
||||||
|
f.write("\n")
|
||||||
|
|
||||||
|
for call_name in sys_call_names:
|
||||||
|
f.write("\t.extern {}\n".format(call_name))
|
||||||
|
|
||||||
|
f.write("\n\t.section jumptable\n\n");
|
||||||
|
|
||||||
|
for call_name in sys_call_names:
|
||||||
|
f.write("sys_{:26}\tjmp long:{}\n".format(call_name + ": ", call_name))
|
213
src/C256/io_stubs.c
Normal file
213
src/C256/io_stubs.c
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "syscalls.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: _Stub_open
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Open a file.
|
||||||
|
* The oflag argument are POSIX style mode flags, e.g O_RDONLY which
|
||||||
|
* are defined in fcntl.h.
|
||||||
|
* This function is variadic as it optionally can take a mode_t that
|
||||||
|
* are permissions, e.g 0666. If the file system does not handle
|
||||||
|
* permissions you can ignore that this function is variadic.
|
||||||
|
* The return file descriptor shall be a positive number, larger
|
||||||
|
* than 2 (as 0-2 are used for stdin, stdout and stderr).
|
||||||
|
* The actual number does not matter and they need not to be
|
||||||
|
* consequtive, multiple numeric series with gaps between can be used.
|
||||||
|
*
|
||||||
|
* Return the obtained file descriptor or EOF (-1) on failure and set
|
||||||
|
* errno according to the error.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
int _Stub_open(const char *path, int oflag, ...) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: _Stub_close
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Close a file
|
||||||
|
*
|
||||||
|
* Return 0 if operation was OK, EOF otherwise and set errno according to
|
||||||
|
* the error.
|
||||||
|
* Note: This will only be invoked for streams opened by _Stub_open(),
|
||||||
|
* there is no need to check for the standard descriptor 0-2.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
int _Stub_close(int fd) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: _Stub_access
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Determine if a file can be accessed.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
int _Stub_access(const char *path, int mode) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: _Stub_lseek
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Change position in a file
|
||||||
|
*
|
||||||
|
* Returns the new position in the file in bytes from the beginning of the
|
||||||
|
* file, or -1 on failure.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
long _Stub_lseek(int fd, long offset, int whence) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: _Stub_fgetpos
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Change position in a file
|
||||||
|
*
|
||||||
|
* Returns 0 on success, non-zero otherwise. In case of an error also set
|
||||||
|
* errno according to error.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
int _Stub_fgetpos(int fd, fpos_t *pos) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: _Stub_fsetpos
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Change position in a file
|
||||||
|
*
|
||||||
|
* Returns 0 on success, non-zero otherwise. In case of an error also set
|
||||||
|
* errno according to error.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
int _Stub_fsetpos(int fd, const fpos_t *pos) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: _Stub_read
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Read from a file
|
||||||
|
*
|
||||||
|
* Returns the number of characters read. Return -1 on failure and set
|
||||||
|
* errno according to the error.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
size_t _Stub_read(int fd, void *buf, size_t count) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: _Stub_write
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Write to a file
|
||||||
|
*
|
||||||
|
* Returns the number of characters actually written. Return -1 on failure and
|
||||||
|
* set errno according to the error.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
size_t _Stub_write(int fd, const void *buf, size_t count) {
|
||||||
|
short channel = 0;
|
||||||
|
|
||||||
|
switch (fd) {
|
||||||
|
case 0:
|
||||||
|
channel = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
channel = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
channel = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
channel = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
sys_txt_put(channel, ((const char *)buf)[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: _Stub_rename
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Rename a file or directory
|
||||||
|
*
|
||||||
|
* Return 0 on success, -1 otherwise and set errno according to the
|
||||||
|
* error.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
int _Stub_rename(const char *oldpath, const char *newpath) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: _Stub_remove
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Remove a file or directory
|
||||||
|
*
|
||||||
|
* Return 0 on success, -1 otherwise and set errno according to the
|
||||||
|
* error.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
int _Stub_remove(const char *path) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: _Stub_exit
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Terminate the program with an exit code, exit clean-ups are done
|
||||||
|
* before this function is (finally) called.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
void _Stub_exit(int exitCode) {
|
||||||
|
while (1) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: _Stub_environ
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Get the environment. On UNIX this is typically a global variable
|
||||||
|
* 'environ', but in order to make it more flexible and avoid having
|
||||||
|
* such global variable (which is not part of the C standard) it is
|
||||||
|
* obtained using the stub interface.
|
||||||
|
*
|
||||||
|
* Note:
|
||||||
|
* This stub function is not implemented by the semi-hosted debug stub
|
||||||
|
* interface.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
char** _Stub_environ(void) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
229
src/C256/jumptable.s
Normal file
229
src/C256/jumptable.s
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
.public sys_proc_exit
|
||||||
|
.public sys_int_enable_all
|
||||||
|
.public sys_int_disable_all
|
||||||
|
.public sys_int_disable
|
||||||
|
.public sys_int_enable
|
||||||
|
.public sys_int_register
|
||||||
|
.public sys_int_pending
|
||||||
|
.public sys_get_info
|
||||||
|
.public sys_int_clear
|
||||||
|
.public sys_chan_read_b
|
||||||
|
.public sys_chan_read
|
||||||
|
.public sys_chan_readline
|
||||||
|
.public sys_chan_write_b
|
||||||
|
.public sys_chan_write
|
||||||
|
.public sys_chan_status
|
||||||
|
.public sys_chan_flush
|
||||||
|
.public sys_chan_seek
|
||||||
|
.public sys_chan_ioctrl
|
||||||
|
.public sys_chan_open
|
||||||
|
.public sys_chan_close
|
||||||
|
.public sys_chan_swap
|
||||||
|
.public sys_chan_device
|
||||||
|
.public sys_cdev_register
|
||||||
|
.public sys_bdev_register
|
||||||
|
.public sys_bdev_read
|
||||||
|
.public sys_bdev_write
|
||||||
|
.public sys_bdev_status
|
||||||
|
.public sys_bdev_flush
|
||||||
|
.public sys_bdev_ioctrl
|
||||||
|
.public sys_fsys_open
|
||||||
|
.public sys_fsys_close
|
||||||
|
.public sys_fsys_opendir
|
||||||
|
.public sys_fsys_closedir
|
||||||
|
.public sys_fsys_readdir
|
||||||
|
.public sys_fsys_findfirst
|
||||||
|
.public sys_fsys_findnext
|
||||||
|
.public sys_fsys_get_label
|
||||||
|
.public sys_fsys_set_label
|
||||||
|
.public sys_fsys_mkdir
|
||||||
|
.public sys_fsys_delete
|
||||||
|
.public sys_fsys_rename
|
||||||
|
.public sys_fsys_set_cwd
|
||||||
|
.public sys_fsys_get_cwd
|
||||||
|
.public sys_fsys_load
|
||||||
|
.public sys_fsys_register_loader
|
||||||
|
.public sys_fsys_stat
|
||||||
|
.public sys_mem_get_ramtop
|
||||||
|
.public sys_mem_reserve
|
||||||
|
.public sys_time_jiffies
|
||||||
|
.public sys_rtc_set_time
|
||||||
|
.public sys_rtc_get_time
|
||||||
|
.public sys_kbd_scancode
|
||||||
|
.public sys_err_message
|
||||||
|
.public sys_kbd_layout
|
||||||
|
.public sys_proc_run
|
||||||
|
.public sys_var_set
|
||||||
|
.public sys_var_get
|
||||||
|
.public sys_txt_get_capabilities
|
||||||
|
.public sys_txt_set_mode
|
||||||
|
.public sys_txt_setsizes
|
||||||
|
.public sys_txt_set_xy
|
||||||
|
.public sys_txt_get_xy
|
||||||
|
.public sys_txt_get_region
|
||||||
|
.public sys_txt_set_region
|
||||||
|
.public sys_txt_set_color
|
||||||
|
.public sys_txt_get_color
|
||||||
|
.public sys_txt_set_cursor_visible
|
||||||
|
.public sys_txt_set_font
|
||||||
|
.public sys_txt_get_sizes
|
||||||
|
.public sys_txt_set_border
|
||||||
|
.public sys_txt_set_border_color
|
||||||
|
.public sys_txt_put
|
||||||
|
.public sys_txt_print
|
||||||
|
|
||||||
|
.extern proc_exit
|
||||||
|
.extern int_enable_all
|
||||||
|
.extern int_disable_all
|
||||||
|
.extern int_disable
|
||||||
|
.extern int_enable
|
||||||
|
.extern int_register
|
||||||
|
.extern int_pending
|
||||||
|
.extern sys_get_information
|
||||||
|
.extern int_clear
|
||||||
|
.extern chan_read_b
|
||||||
|
.extern chan_read
|
||||||
|
.extern chan_readline
|
||||||
|
.extern chan_write_b
|
||||||
|
.extern chan_write
|
||||||
|
.extern chan_status
|
||||||
|
.extern chan_flush
|
||||||
|
.extern chan_seek
|
||||||
|
.extern chan_ioctrl
|
||||||
|
.extern chan_open
|
||||||
|
.extern chan_close
|
||||||
|
.extern chan_swap
|
||||||
|
.extern chan_device
|
||||||
|
.extern cdev_register
|
||||||
|
.extern bdev_register
|
||||||
|
.extern bdev_read
|
||||||
|
.extern bdev_write
|
||||||
|
.extern bdev_status
|
||||||
|
.extern bdev_flush
|
||||||
|
.extern bdev_ioctrl
|
||||||
|
.extern fsys_open
|
||||||
|
.extern fsys_close
|
||||||
|
.extern fsys_opendir
|
||||||
|
.extern fsys_closedir
|
||||||
|
.extern fsys_readdir
|
||||||
|
.extern fsys_findfirst
|
||||||
|
.extern fsys_findnext
|
||||||
|
.extern fsys_getlabel
|
||||||
|
.extern fsys_setlabel
|
||||||
|
.extern fsys_mkdir
|
||||||
|
.extern fsys_delete
|
||||||
|
.extern fsys_rename
|
||||||
|
.extern fsys_set_cwd
|
||||||
|
.extern fsys_get_cwd
|
||||||
|
.extern fsys_load
|
||||||
|
.extern fsys_register_loader
|
||||||
|
.extern fsys_stat
|
||||||
|
.extern mem_get_ramtop
|
||||||
|
.extern mem_reserve
|
||||||
|
.extern timers_jiffies
|
||||||
|
.extern rtc_set_time
|
||||||
|
.extern rtc_get_time
|
||||||
|
.extern kbd_get_scancode
|
||||||
|
.extern err_message
|
||||||
|
.extern kbd_layout
|
||||||
|
.extern proc_run
|
||||||
|
; .extern var_set
|
||||||
|
; .extern var_get
|
||||||
|
.extern txt_get_capabilities
|
||||||
|
.extern txt_set_mode
|
||||||
|
.extern txt_setsizes
|
||||||
|
.extern txt_set_xy
|
||||||
|
.extern txt_get_xy
|
||||||
|
.extern txt_get_region
|
||||||
|
.extern txt_set_region
|
||||||
|
.extern txt_set_color
|
||||||
|
.extern txt_get_color
|
||||||
|
.extern txt_set_cursor_visible
|
||||||
|
.extern txt_set_font
|
||||||
|
.extern txt_get_sizes
|
||||||
|
.extern txt_set_border
|
||||||
|
.extern txt_set_border_color
|
||||||
|
.extern txt_put
|
||||||
|
.extern txt_print
|
||||||
|
|
||||||
|
.section jumptable
|
||||||
|
|
||||||
|
sys_proc_exit: jmp long:proc_exit
|
||||||
|
sys_int_enable_all: jmp long:int_enable_all
|
||||||
|
sys_int_disable_all: jmp long:int_disable_all
|
||||||
|
sys_int_disable: jmp long:int_disable
|
||||||
|
sys_int_enable: jmp long:int_enable
|
||||||
|
sys_int_register: jmp long:int_register
|
||||||
|
sys_int_pending: jmp long:int_pending
|
||||||
|
sys_get_info: jmp long:sys_get_information
|
||||||
|
sys_int_clear: jmp long:int_clear
|
||||||
|
sys_chan_read_b: jmp long:chan_read_b
|
||||||
|
sys_chan_read: jmp long:chan_read
|
||||||
|
sys_chan_readline: jmp long:chan_readline
|
||||||
|
sys_chan_write_b: jmp long:chan_write_b
|
||||||
|
sys_chan_write: jmp long:chan_write
|
||||||
|
sys_chan_status: jmp long:chan_status
|
||||||
|
sys_chan_flush: jmp long:chan_flush
|
||||||
|
sys_chan_seek: jmp long:chan_seek
|
||||||
|
sys_chan_ioctrl: jmp long:chan_ioctrl
|
||||||
|
sys_chan_open: jmp long:chan_open
|
||||||
|
sys_chan_close: jmp long:chan_close
|
||||||
|
sys_chan_swap: jmp long:chan_swap
|
||||||
|
sys_chan_device: jmp long:chan_device
|
||||||
|
sys_cdev_register: jmp long:cdev_register
|
||||||
|
sys_bdev_register: jmp long:bdev_register
|
||||||
|
sys_bdev_read: jmp long:bdev_read
|
||||||
|
sys_bdev_write: jmp long:bdev_write
|
||||||
|
sys_bdev_status: jmp long:bdev_status
|
||||||
|
sys_bdev_flush: jmp long:bdev_flush
|
||||||
|
sys_bdev_ioctrl: jmp long:bdev_ioctrl
|
||||||
|
sys_fsys_open: jmp long:fsys_open
|
||||||
|
sys_fsys_close: jmp long:fsys_close
|
||||||
|
sys_fsys_opendir: jmp long:fsys_opendir
|
||||||
|
sys_fsys_closedir: jmp long:fsys_closedir
|
||||||
|
sys_fsys_readdir: jmp long:fsys_readdir
|
||||||
|
sys_fsys_findfirst: jmp long:fsys_findfirst
|
||||||
|
sys_fsys_findnext: jmp long:fsys_findnext
|
||||||
|
sys_fsys_get_label: jmp long:fsys_getlabel
|
||||||
|
sys_fsys_set_label: jmp long:fsys_setlabel
|
||||||
|
sys_fsys_mkdir: jmp long:fsys_mkdir
|
||||||
|
sys_fsys_delete: jmp long:fsys_delete
|
||||||
|
sys_fsys_rename: jmp long:fsys_rename
|
||||||
|
sys_fsys_set_cwd: jmp long:fsys_set_cwd
|
||||||
|
sys_fsys_get_cwd: jmp long:fsys_get_cwd
|
||||||
|
sys_fsys_load: jmp long:fsys_load
|
||||||
|
sys_fsys_register_loader: jmp long:fsys_register_loader
|
||||||
|
sys_fsys_stat: jmp long:fsys_stat
|
||||||
|
sys_mem_get_ramtop: jmp long:mem_get_ramtop
|
||||||
|
sys_mem_reserve: jmp long:mem_reserve
|
||||||
|
sys_time_jiffies: jmp long:timers_jiffies
|
||||||
|
sys_rtc_set_time: jmp long:rtc_set_time
|
||||||
|
sys_rtc_get_time: jmp long:rtc_get_time
|
||||||
|
sys_kbd_scancode: jmp long:kbd_get_scancode
|
||||||
|
sys_err_message: jmp long:err_message
|
||||||
|
sys_kbd_layout: jmp long:kbd_layout
|
||||||
|
sys_proc_run: jmp long:proc_run
|
||||||
|
sys_var_set: brk ; jmp long:var_set
|
||||||
|
brk
|
||||||
|
brk
|
||||||
|
brk
|
||||||
|
sys_var_get: brk ; jmp long:var_get
|
||||||
|
brk
|
||||||
|
brk
|
||||||
|
brk
|
||||||
|
sys_txt_get_capabilities: jmp long:txt_get_capabilities
|
||||||
|
sys_txt_set_mode: jmp long:txt_set_mode
|
||||||
|
sys_txt_setsizes: jmp long:txt_setsizes
|
||||||
|
sys_txt_set_xy: jmp long:txt_set_xy
|
||||||
|
sys_txt_get_xy: jmp long:txt_get_xy
|
||||||
|
sys_txt_get_region: jmp long:txt_get_region
|
||||||
|
sys_txt_set_region: jmp long:txt_set_region
|
||||||
|
sys_txt_set_color: jmp long:txt_set_color
|
||||||
|
sys_txt_get_color: jmp long:txt_get_color
|
||||||
|
sys_txt_set_cursor_visible: jmp long:txt_set_cursor_visible
|
||||||
|
sys_txt_set_font: jmp long:txt_set_font
|
||||||
|
sys_txt_get_sizes: jmp long:txt_get_sizes
|
||||||
|
sys_txt_set_border: jmp long:txt_set_border
|
||||||
|
sys_txt_set_border_color: jmp long:txt_set_border_color
|
||||||
|
sys_txt_put: jmp long:txt_put
|
||||||
|
sys_txt_print: jmp long:txt_print
|
24
src/C256/ld_lc_c256_fmx.scm
Normal file
24
src/C256/ld_lc_c256_fmx.scm
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
(define memories
|
||||||
|
'((memory flash (address (#x390000 . #x3fffff))
|
||||||
|
(type rom))
|
||||||
|
(memory DirectPage (address (#x00c000 . #x00c0ff))
|
||||||
|
(section (registers ztiny)))
|
||||||
|
(memory LoRAM (address (#x00c100 . #x00efff))
|
||||||
|
(section stack data zdata data heap))
|
||||||
|
(memory NearRAM1 (address (#x010000 . #x017fff))
|
||||||
|
(section znear near))
|
||||||
|
(memory NearRAM2 (address (#x018000 . #x01ffff))
|
||||||
|
(section cnear))
|
||||||
|
(memory FarRAM1 (address (#x020000 . #x02ffff))
|
||||||
|
(section far huge))
|
||||||
|
(memory FarRAM2 (address (#x030000 . #x03ffff))
|
||||||
|
(section zfar zhuge ))
|
||||||
|
(memory LoCODE (address (#x00f000 . #x00ffdf))
|
||||||
|
(section code cdata (jumptable #x00f000)))
|
||||||
|
(memory Vector (address (#x00ffe0 . #x00ffff))
|
||||||
|
(section (reset #xfffc)))
|
||||||
|
(block stack (size #x1000))
|
||||||
|
(block heap (size #x1000))
|
||||||
|
(base-address _DirectPageStart DirectPage 0)
|
||||||
|
(base-address _NearBaseAddress NearRAM1 0)
|
||||||
|
))
|
80
src/C256/syscalls.txt
Normal file
80
src/C256/syscalls.txt
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
# A list of system calls to be used to autogenerate the various jump tables and sys calls stubs\
|
||||||
|
|
||||||
|
proc_exit
|
||||||
|
int_enable_all
|
||||||
|
int_disable_all
|
||||||
|
int_disable
|
||||||
|
int_enable
|
||||||
|
int_register
|
||||||
|
int_pending
|
||||||
|
get_info
|
||||||
|
int_clear
|
||||||
|
|
||||||
|
chan_read_b
|
||||||
|
chan_read
|
||||||
|
chan_readline
|
||||||
|
chan_write_b
|
||||||
|
chan_write
|
||||||
|
chan_status
|
||||||
|
chan_flush
|
||||||
|
chan_seek
|
||||||
|
chan_ioctrl
|
||||||
|
chan_open
|
||||||
|
chan_close
|
||||||
|
chan_swap
|
||||||
|
chan_device
|
||||||
|
chan_register
|
||||||
|
|
||||||
|
bdev_register
|
||||||
|
bdev_read
|
||||||
|
bdev_write
|
||||||
|
bdev_status
|
||||||
|
bdev_flush
|
||||||
|
bdev_ioctrl
|
||||||
|
|
||||||
|
fsys_open
|
||||||
|
fsys_close
|
||||||
|
fsys_opendir
|
||||||
|
fsys_closedir
|
||||||
|
fsys_readdir
|
||||||
|
fsys_findfirst
|
||||||
|
fsys_findnext
|
||||||
|
fsys_get_label
|
||||||
|
fsys_set_label
|
||||||
|
fsys_mkdir
|
||||||
|
fsys_delete
|
||||||
|
fsys_rename
|
||||||
|
fsys_set_cwd
|
||||||
|
fsys_get_cwd
|
||||||
|
fsys_load
|
||||||
|
fsys_register_loader
|
||||||
|
fsys_stat
|
||||||
|
|
||||||
|
mem_get_ramtop
|
||||||
|
mem_reserve
|
||||||
|
time_jiffies
|
||||||
|
rtc_set_time
|
||||||
|
rtc_get_time
|
||||||
|
kbd_scancode
|
||||||
|
err_message
|
||||||
|
kbd_layout
|
||||||
|
proc_run
|
||||||
|
var_set
|
||||||
|
var_get
|
||||||
|
|
||||||
|
txt_get_capabilities
|
||||||
|
txt_set_mode
|
||||||
|
txt_setsizes
|
||||||
|
txt_set_xy
|
||||||
|
txt_get_xy
|
||||||
|
txt_get_region
|
||||||
|
txt_set_region
|
||||||
|
txt_set_color
|
||||||
|
txt_get_color
|
||||||
|
txt_set_cursor_visible
|
||||||
|
txt_set_font
|
||||||
|
txt_get_sizes
|
||||||
|
txt_set_border
|
||||||
|
txt_set_border_color
|
||||||
|
txt_put
|
||||||
|
txt_print
|
94
src/Makefile
Normal file
94
src/Makefile
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
# VPATH=.:../../module/Calypsi-remote-debug/src
|
||||||
|
DEBUGGER=../module/Calypsi-remote-debug/src
|
||||||
|
|
||||||
|
UNIT := C256U_PLUS
|
||||||
|
MEMORY := RAM
|
||||||
|
|
||||||
|
# Define OS-dependent variables
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
RM = del /F/Q
|
||||||
|
else
|
||||||
|
RM = rm -f
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Define model-specific variables, including tools, source files, compiler flags, etc.
|
||||||
|
|
||||||
|
ifeq ($(UNIT),C256U)
|
||||||
|
CPU=w65816
|
||||||
|
C_SRCS_DEBUGGER=$(DEBUGGER)/agent.c $(DEBUGGER)/c256-uart.c $(DEBUGGER)/low_level_WDC65816.s
|
||||||
|
SRCS_FOR_UNIT=
|
||||||
|
CFLAGS_FOR_UNIT=-DMODEL=1 -DCPU=255 --code-model large --data-model large
|
||||||
|
LDFLAGS_FOR_UNIT=C256/ld_lc_c256_u.scm clib-lc-ld.a
|
||||||
|
else ifeq ($(UNIT),C256U_PLUS)
|
||||||
|
CPU=w65816
|
||||||
|
C_SRCS_DEBUGGER=$(DEBUGGER)/agent.c $(DEBUGGER)/c256-uart.c $(DEBUGGER)/low_level_WDC65816.s
|
||||||
|
SRCS_FOR_UNIT=C256/jumptable.s C256/io_stubs.c C256/extras.s
|
||||||
|
CFLAGS_FOR_UNIT=-DMODEL=5 -DCPU=255 --code-model large --data-model large
|
||||||
|
|
||||||
|
ifeq ($(MEMORY),ROM)
|
||||||
|
LDFLAGS_FOR_UNIT=C256/flash-u-plus.scm clib-lc-ld.a --rtattr printf=medium
|
||||||
|
else
|
||||||
|
LDFLAGS_FOR_UNIT=C256/ld_lc_c256_fmx.scm clib-lc-ld.a --rtattr printf=medium
|
||||||
|
endif
|
||||||
|
else ifeq ($(UNIT),C256_FMX)
|
||||||
|
CPU=w65816
|
||||||
|
C_SRCS_DEBUGGER=$(DEBUGGER)/agent.c $(DEBUGGER)/c256-uart.c $(DEBUGGER)/low_level_WDC65816.s
|
||||||
|
SRCS_FOR_UNIT=
|
||||||
|
CFLAGS_FOR_UNIT=-DMODEL=0 -DCPU=255 --code-model large --data-model large
|
||||||
|
LDFLAGS_FOR_UNIT=C256/ld_lc_c256_fmx.scm clib-lc-ld.a
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CPU),w65816)
|
||||||
|
CC=cc65816
|
||||||
|
AS=as65816
|
||||||
|
LD=ln65816
|
||||||
|
AR=nlib
|
||||||
|
endif
|
||||||
|
|
||||||
|
INCLUDES=-I. -I./include
|
||||||
|
CFLAGS=$(INCLUDES) $(CFLAGS_FOR_UNIT) # -l -D_CALYPSI_MCP_DEBUGGER
|
||||||
|
ASFLAGS=$(INCLUDES)
|
||||||
|
|
||||||
|
ifeq ($(MEMORY),ROM)
|
||||||
|
LDFLAGS=--rom-code $(LDFLAGS_FOR_UNIT) --list-file toolbox.map
|
||||||
|
else
|
||||||
|
LDFLAGS=$(LDFLAGS_FOR_UNIT) --list-file toolbox.map
|
||||||
|
endif
|
||||||
|
|
||||||
|
SRCS = toolbox.c log.c memory.c proc.c ring_buffer.c simpleio.c sys_general.c utilities.c $(SRCS_FOR_UNIT) # $(C_SRCS_DEBUGGER)
|
||||||
|
OBJS = $(patsubst %.s,%.o,$(patsubst %.c,%.o,$(SRCS)))
|
||||||
|
OBJS4RM = $(subst /,\\,$(OBJS))
|
||||||
|
LIBS = dev/devices.a snd/sound.a fatfs/fatfs.a
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
|
||||||
|
toolbox.s37: $(OBJS) $(LIBS)
|
||||||
|
$(LD) $(LDFLAGS) --output-format s37 -o $@ $^
|
||||||
|
|
||||||
|
toolbox.raw: $(OBJS) $(LIBS)
|
||||||
|
$(LD) $(LDFLAGS) --output-format raw -o $@ $^
|
||||||
|
|
||||||
|
dev/devices.a:
|
||||||
|
$(MAKE) --directory=dev
|
||||||
|
|
||||||
|
snd/sound.a:
|
||||||
|
$(MAKE) --directory=snd
|
||||||
|
|
||||||
|
fatfs/fatfs.a:
|
||||||
|
$(MAKE) --directory=fatfs
|
||||||
|
|
||||||
|
# Build the object files from C
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
# Build the object files from assembly
|
||||||
|
%.o: %.s
|
||||||
|
$(AS) $(ASFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
# Clean up after a build
|
||||||
|
clean:
|
||||||
|
$(RM) $(OBJS4RM) toolbox.s37 *.lst *.map
|
||||||
|
$(MAKE) --directory=dev clean
|
||||||
|
$(MAKE) --directory=snd clean
|
||||||
|
$(MAKE) --directory=fatfs clean
|
629
src/boot.c
Normal file
629
src/boot.c
Normal file
|
@ -0,0 +1,629 @@
|
||||||
|
/**
|
||||||
|
* @file boot.c
|
||||||
|
*
|
||||||
|
* Routines to support the boot process
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "log_level.h"
|
||||||
|
#ifndef DEFAULT_LOG_LEVEL
|
||||||
|
#define DEFAULT_LOG_LEVEL LOG_TRACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "sys_general.h"
|
||||||
|
#include "boot.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "errors.h"
|
||||||
|
#include "gabe_reg.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "simpleio.h"
|
||||||
|
#include "syscalls.h"
|
||||||
|
#include "vicky_general.h"
|
||||||
|
#include "cli/cli.h"
|
||||||
|
#include "dev/kbd_mo.h"
|
||||||
|
#include "dev/txt_screen.h"
|
||||||
|
|
||||||
|
#include "rsrc/font/quadrotextFONT.h"
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560U || MODEL == MODEL_FOENIX_A2560U_PLUS
|
||||||
|
#include "rsrc/bitmaps/splash_a2560u.h"
|
||||||
|
#include "dev/txt_a2560u.h"
|
||||||
|
#elif MODEL == MODEL_FOENIX_A2560K
|
||||||
|
#include "rsrc/bitmaps/splash_a2560k.h"
|
||||||
|
#elif MODEL == MODEL_FOENIX_A2560X || MODEL == MODEL_FOENIX_GENX
|
||||||
|
#include "rsrc/bitmaps/splash_a2560x.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K
|
||||||
|
#define SPLASH_WAIT_SEC 10 /* How many seconds to wait on the splash screen */
|
||||||
|
#else
|
||||||
|
#define SPLASH_WAIT_SEC 4 /* How many seconds to wait on the splash screen */
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Important scan codes
|
||||||
|
*/
|
||||||
|
#define SC_F1 0x3B
|
||||||
|
#define SC_F2 0x3C
|
||||||
|
#define SC_F3 0x3D
|
||||||
|
#define SC_SPACE 0x39
|
||||||
|
#define SC_RETURN 0x1C
|
||||||
|
|
||||||
|
/* TODO: move this to constants.h */
|
||||||
|
|
||||||
|
|
||||||
|
#define BOOT_SECTOR_BUFFER ((unsigned char *)0x00004000)
|
||||||
|
#define BOOT_CODE_MBR_OFF 0x000 /* Offset to the code in the MBR */
|
||||||
|
#define BOOT_CPUID_MBR_OFF 0x004 /* Offset to the CPUID in the MBR */
|
||||||
|
#define BOOT_SIG_MBR_OFF 0x006 /* Offset to the boot signature in the MBR */
|
||||||
|
#define BOOT_SIG 0xF0E1 /* Foenix/MCP boot signature expected */
|
||||||
|
|
||||||
|
#define FDC_VBR_JUMP 0x000 // Intel 80x86 machine language jump... 3 bytes
|
||||||
|
#define FDC_VBR_OEMNAME 0x003 // OEM Name... 8 bytes
|
||||||
|
#define FDC_VBR_BPB 0x00B // BIOS Parameter Block
|
||||||
|
#define FDC_VBR_BYTES_PER_SECTOR 0x00B // Number of bytes per sector... 2 bytes
|
||||||
|
#define FDC_VBR_SECTORS_PER_CLUSTER 0x00D // Number of sectors per cluster... 1 byte
|
||||||
|
#define FDC_VBR_RESERVED_SECTORS 0x00E // Number of reserved sectors... 2 bytes
|
||||||
|
#define FDC_VBR_FAT_COUNT 0x010 // Number of file allocation tables... 1 byte
|
||||||
|
#define FDC_VBR_MAX_ROOT_ENTRIES 0x011 // Maximum number of root directory entries... 2 bytes
|
||||||
|
#define FDC_VBR_SECTORS 0x013 // Number of logical sectors in FAT12/16... 2 bytes
|
||||||
|
#define FDC_VBR_MEDIA_TYPE 0x015 // Media type code... 1 byte
|
||||||
|
#define FDC_VBR_SECTORS_PER_FAT 0x016 // Number of sectors per file allocation table... 2 bytes
|
||||||
|
#define FDC_VBR_SECTORS_PER_TRACK 0x018 // Number of sectors per track... 2 bytes
|
||||||
|
#define FDC_VBR_HEADS 0x01A // Number of heads... 2 bytes
|
||||||
|
#define FDC_VBR_HIDDEN_SECTORS 0x01C // Number of hidden sectors... 2 bytes
|
||||||
|
#define FDC_VBR_TOTAL_SECTORS 0x01E // Total number of sectors... 2 bytes
|
||||||
|
#define FDC_VBR_BOOT_CODE 0x060 // Start of boot sector code
|
||||||
|
|
||||||
|
#define BOOT_CODE_VBR_OFF FDC_VBR_BOOT_CODE /* Offset to the code in the VBR for floppy drives */
|
||||||
|
#define BOOT_CPUID_VBR_OFF BOOT_CODE_VBR_OFF+4 /* Offset to the CPUID in the VBR for floppy drives */
|
||||||
|
#define BOOT_SIG_VBR_OFF BOOT_CODE_VBR_OFF+6 /* Offset to the boot signature in the VBR for floppy drives */
|
||||||
|
|
||||||
|
const char * MCP_INIT_SDC = "/sd/system/mcp.init"; /**< Path to config file on the SD card */
|
||||||
|
const char * MCP_INIT_FDC = "/fd/system/mcp.init"; /**< Path to config file on the floppy drive */
|
||||||
|
const char * MCP_INIT_HDC = "/hd/system/mcp.init"; /**< Path to config file on the IDE drive */
|
||||||
|
|
||||||
|
// Colors for the A2560K keyboard LED matrix
|
||||||
|
const unsigned short kbd_colors[] = {0x000F, 0x0FF, 0x00F0, 0x0FF0, 0x0F70, 0x0F00};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On the A2560K, animate the LEDs based on the current time while we're waiting for a key press
|
||||||
|
*
|
||||||
|
* @param max_ticks the value of the jiffy counter when the boot screen will end
|
||||||
|
* @param ticks the current value of the jiffy counter
|
||||||
|
* @param min_ticks the starting value of the jiffy counter
|
||||||
|
*/
|
||||||
|
void boot_animate_keyboard(unsigned long max_ticks, unsigned long ticks, unsigned long min_ticks) {
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K
|
||||||
|
const int animation_steps = 7;
|
||||||
|
int current_step = (int)(((ticks - min_ticks) * animation_steps) / (max_ticks - min_ticks));
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < current_step; i++) {
|
||||||
|
kbdmo_set_led_matrix_row(current_step - i - 1, kbd_colors[5 - i]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a sector loaded from a device is bootable
|
||||||
|
*
|
||||||
|
* @param sector pointer to where the sector is stored in memory
|
||||||
|
* @param device the number of the block device
|
||||||
|
*
|
||||||
|
* @return 0 if not bootable, non-zero if bootable
|
||||||
|
*/
|
||||||
|
bool is_bootable(unsigned char * sector, short device) {
|
||||||
|
switch(device) {
|
||||||
|
case BDEV_FDC:
|
||||||
|
// The SDC and HDC boot off the MBR...
|
||||||
|
// Check for the CPUID and boot signature
|
||||||
|
if ((sector[BOOT_CPUID_VBR_OFF] == CPU_M68000) ||
|
||||||
|
(sector[BOOT_CPUID_VBR_OFF] == CPU_M68040)) {
|
||||||
|
if ((sector[BOOT_SIG_VBR_OFF] == ((BOOT_SIG >> 8) & 0x00FF)) &&
|
||||||
|
(sector[BOOT_SIG_VBR_OFF+1] == (BOOT_SIG & 0x00FF))) {
|
||||||
|
// The CPU is supported, and the boot signature is correct
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BDEV_SDC:
|
||||||
|
case BDEV_HDC:
|
||||||
|
// The SDC and HDC boot off the MBR...
|
||||||
|
// Check for the CPUID and boot signature
|
||||||
|
if ((sector[BOOT_CPUID_MBR_OFF] == CPU_M68000) ||
|
||||||
|
(sector[BOOT_CPUID_MBR_OFF] == CPU_M68040)) {
|
||||||
|
if ((sector[BOOT_SIG_MBR_OFF] == ((BOOT_SIG >> 8) & 0x00FF)) &&
|
||||||
|
(sector[BOOT_SIG_MBR_OFF+1] == (BOOT_SIG & 0x00FF))) {
|
||||||
|
// The CPU is supported, and the boot signature is correct
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Otherwise: we're not bootable
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have reached this point, the sector is not bootable
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the code in the boot sector
|
||||||
|
*
|
||||||
|
* @param device the number of the block device for the sector
|
||||||
|
*/
|
||||||
|
void boot_sector_run(short device) {
|
||||||
|
FUNC_V_2_V boot_sector = 0;
|
||||||
|
|
||||||
|
switch(device) {
|
||||||
|
case BDEV_FDC:
|
||||||
|
// The FDC boots off the Volume Boot Record (offset 0x060)
|
||||||
|
boot_sector = (FUNC_V_2_V)(BOOT_SECTOR_BUFFER + BOOT_CODE_VBR_OFF);
|
||||||
|
boot_sector();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BDEV_SDC:
|
||||||
|
case BDEV_HDC:
|
||||||
|
// The SDC and HDC both boot off the MBR
|
||||||
|
boot_sector = (FUNC_V_2_V)(BOOT_SECTOR_BUFFER);
|
||||||
|
boot_sector();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void make_key_name(const char * original, char * buffer) {
|
||||||
|
int x;
|
||||||
|
for (x = 0; x < strlen(original); x++) {
|
||||||
|
buffer[x] = 0x80 | original[x];
|
||||||
|
}
|
||||||
|
buffer[strlen(original)] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load and display the boot splash screen on the graphics screen
|
||||||
|
*
|
||||||
|
* @return boot device selected by user
|
||||||
|
*/
|
||||||
|
short boot_screen() {
|
||||||
|
t_rect region;
|
||||||
|
short device = BOOT_DEFAULT;
|
||||||
|
short screen;
|
||||||
|
char buffer[256];
|
||||||
|
char entry[50];
|
||||||
|
unsigned long target_jiffies = 0;
|
||||||
|
unsigned long min_jiffies = 0;
|
||||||
|
unsigned long current_jiffies = 0;
|
||||||
|
int i = 0;
|
||||||
|
const unsigned char * pixels;
|
||||||
|
volatile unsigned char * vram = VRAM_Bank0;
|
||||||
|
t_sys_info info;
|
||||||
|
char f1[3], f2[3], f3[3];
|
||||||
|
char space[10], cr_text[10];
|
||||||
|
|
||||||
|
TRACE("boot_screen");
|
||||||
|
|
||||||
|
// We'll display boot information on the common screen
|
||||||
|
screen = 0;
|
||||||
|
|
||||||
|
/* Turn off the screen */
|
||||||
|
txt_set_mode(screen, 0);
|
||||||
|
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
LUT_0[4*i] = splashscreen_lut[4*i];
|
||||||
|
LUT_0[4*i+1] = splashscreen_lut[4*i+1];
|
||||||
|
LUT_0[4*i+2] = splashscreen_lut[4*i+2];
|
||||||
|
LUT_0[4*i+3] = splashscreen_lut[4*i+3];
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
/* Copy the bitmap to video RAM, it has simple RLE compression */
|
||||||
|
for (pixels = splashscreen_pix; *pixels != 0;) {
|
||||||
|
unsigned char count = *pixels++;
|
||||||
|
unsigned char pixel = *pixels++;
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
*vram++ = pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#if 0
|
||||||
|
// For debug, try something more basic
|
||||||
|
const line_len = 640;
|
||||||
|
//memset(vram, 1, 640*480);
|
||||||
|
for (i=0; i < 640*480; i++)
|
||||||
|
vram[i] = 3;
|
||||||
|
for (i = 0; i < 480; i++)
|
||||||
|
vram[640*i + i] = 2;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
/* Set up the bitmap */
|
||||||
|
*BM0_Addy_Pointer_Reg = 0; /* Start of VRAM */
|
||||||
|
*BM0_Control_Reg = 1;
|
||||||
|
|
||||||
|
/* Set a background color for the bitmap mode */
|
||||||
|
#if HAS_DUAL_SCREEN
|
||||||
|
*BackGroundControlReg_B = 0x00202020;
|
||||||
|
screen = 0;
|
||||||
|
#else
|
||||||
|
*BackGroundControlReg_A = 0x00402040;
|
||||||
|
screen = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Display the splashscreen at 640x480 without a border */
|
||||||
|
txt_set_resolution(screen, 640, 480);
|
||||||
|
txt_set_border(screen, 0, 0);
|
||||||
|
txt_set_font(screen, 8, 8, quadrotextFONT);
|
||||||
|
|
||||||
|
region.origin.x = 0;
|
||||||
|
region.origin.y = 0;
|
||||||
|
region.size.width = 0;
|
||||||
|
region.size.height = 0;
|
||||||
|
txt_set_region(screen, ®ion);
|
||||||
|
txt_setsizes(screen);
|
||||||
|
txt_set_mode(screen, TXT_MODE_TEXT | TXT_MODE_BITMAP);
|
||||||
|
|
||||||
|
/* Disable the cursor, set the color, clear the text screen, and display the text message */
|
||||||
|
txt_set_cursor(screen, 0, 0, 0); // Disable the cursor
|
||||||
|
txt_set_color(screen, 15, 0); // White on transparent
|
||||||
|
txt_fill(screen, ' '); // Clear the screen
|
||||||
|
|
||||||
|
make_key_name("F1", f1);
|
||||||
|
make_key_name("F2", f2);
|
||||||
|
make_key_name("F3", f3);
|
||||||
|
make_key_name("SPACE", space);
|
||||||
|
make_key_name("RETURN", cr_text);
|
||||||
|
|
||||||
|
#if HAS_FLOPPY
|
||||||
|
sprintf(buffer, "BOOT: %s=SD CARD, %s=HARD DRIVE, s=FLOPPY, %s=DEFAULT, %s=SAFE", f1, f2, f3, space, cr_text);
|
||||||
|
#else
|
||||||
|
sprintf(buffer, "BOOT: %s=SD CARD, %s=HARD DRIVE, %s=DEFAULT, %s=SAFE", f1, f2, space, cr_text);
|
||||||
|
#endif
|
||||||
|
txt_set_xy(screen, (80 - strlen(buffer)) / 2, 58);
|
||||||
|
sys_chan_write(screen, buffer, strlen(buffer));
|
||||||
|
|
||||||
|
// Get the information about the system
|
||||||
|
sys_get_info(&info);
|
||||||
|
|
||||||
|
region.origin.x = 49;
|
||||||
|
region.origin.y = 1;
|
||||||
|
region.size.width = 40;
|
||||||
|
region.size.height = 20;
|
||||||
|
txt_set_region(screen, ®ion);
|
||||||
|
|
||||||
|
sprintf(buffer, "\x1b[HFOENIX/MCP V: %02u.%04u.%04u\n", info.mcp_version, info.mcp_rev, info.mcp_build);
|
||||||
|
print(screen, buffer);
|
||||||
|
str_upcase(info.model_name, entry);
|
||||||
|
sprintf(buffer, " MODEL: %s\n", entry);
|
||||||
|
print(screen, buffer);
|
||||||
|
str_upcase(info.cpu_name, entry);
|
||||||
|
sprintf(buffer, " CPU: %s\n", entry);
|
||||||
|
print(screen, buffer);
|
||||||
|
sprintf(buffer, " CLOCK (KHZ): %u\n", info.cpu_clock_khz);
|
||||||
|
print(screen, buffer);
|
||||||
|
sprintf(buffer, " FPGA V: %u.%02u.%04u\n", (unsigned int)info.fpga_model, info.fpga_version, info.fpga_subver);
|
||||||
|
print(screen, buffer);
|
||||||
|
|
||||||
|
/* Wait until the target duration has been reached _or_ the user presses a key */
|
||||||
|
sprintf(buffer, "Booting from default device...\n");
|
||||||
|
min_jiffies = sys_time_jiffies();
|
||||||
|
target_jiffies = min_jiffies + SPLASH_WAIT_SEC * 60;
|
||||||
|
|
||||||
|
while (target_jiffies > (current_jiffies = sys_time_jiffies())) {
|
||||||
|
boot_animate_keyboard(target_jiffies, current_jiffies, min_jiffies);
|
||||||
|
|
||||||
|
unsigned short scan_code = sys_kbd_scancode();
|
||||||
|
if (scan_code == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (scan_code) {
|
||||||
|
case SC_F1:
|
||||||
|
device = BDEV_SDC;
|
||||||
|
strcpy(buffer, "Booting from SD card.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SC_F2:
|
||||||
|
device = BDEV_HDC;
|
||||||
|
strcpy(buffer, "Booting from hard drive.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if HAS_FLOPPY
|
||||||
|
case SC_F3:
|
||||||
|
device = BDEV_FDC;
|
||||||
|
strcpy(buffer, "Booting from floppy drive.\n");
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case SC_RETURN:
|
||||||
|
device = BOOT_SAFE;
|
||||||
|
strcpy(buffer, "Booting directly to the command line.\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
device = BOOT_DEFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialise all screens */
|
||||||
|
txt_init_screen(screen); /* This is the one used for the boot message */
|
||||||
|
/* No need to txt_set_resolution(screen, 0, 0) because during screen_init, the defaults are applied */
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K || MODEL == MODEL_FOENIX_A2560X || MODEL == MODEL_FOENIX_GENX
|
||||||
|
txt_set_resolution(1, 0, 0); // Set the resolution based on the DIP switch
|
||||||
|
#endif
|
||||||
|
print(screen, buffer);
|
||||||
|
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K
|
||||||
|
// Turn off the keyboard LEDs
|
||||||
|
kbdmo_set_led_matrix_fill(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the boot process after initializing the MCP
|
||||||
|
*
|
||||||
|
* @param device the number of the block device to use for booting (-1 to go straight to CLI)
|
||||||
|
*/
|
||||||
|
void boot_from_bdev(short device) {
|
||||||
|
char initial_path[10];
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K
|
||||||
|
unsigned int boot_dip = 0; // The setting on the user and boot mode DIP switches
|
||||||
|
#elif MODEL == MODEL_FOENIX_GENX || MODEL == MODEL_FOENIX_A2560X || MODEL_FOENIX_A2560U_PLUS
|
||||||
|
unsigned short boot_dip = 0; // The setting on the user and boot mode DIP switches
|
||||||
|
#endif
|
||||||
|
short bootable = 0; // Is the boot sector of the selected device bootable?
|
||||||
|
|
||||||
|
TRACE1("boot_from_bdev(%d)", device);
|
||||||
|
|
||||||
|
initial_path[0] = '\0';
|
||||||
|
|
||||||
|
// Get the boot device
|
||||||
|
switch (device) {
|
||||||
|
case BOOT_DEFAULT:
|
||||||
|
// User chose the default. Look at the DIP switches to determine the boot source
|
||||||
|
boot_dip = *GABE_DIP_REG & GABE_DIP_BOOT_MASK;
|
||||||
|
switch (boot_dip) {
|
||||||
|
case 0x0000:
|
||||||
|
// Boot from IDE
|
||||||
|
device = BDEV_HDC;
|
||||||
|
log(LOG_INFO, "Boot DIP set for IDE");
|
||||||
|
strcpy(initial_path, "/hd");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0001:
|
||||||
|
// Boot from SDC
|
||||||
|
device = BDEV_SDC;
|
||||||
|
log(LOG_INFO, "Boot DIP set for SDC");
|
||||||
|
strcpy(initial_path, "/sd");
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if HAS_FLOPPY
|
||||||
|
case 0x0002:
|
||||||
|
// Boot from Floppy
|
||||||
|
device = BDEV_FDC;
|
||||||
|
log(LOG_INFO, "Boot DIP set for FDC");
|
||||||
|
strcpy(initial_path, "/fd");
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
// Boot straight to REPL
|
||||||
|
log(LOG_INFO, "Boot DIP set for REPL");
|
||||||
|
strcpy(initial_path, "/sd");
|
||||||
|
device = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device >= 0) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 512; i++) {
|
||||||
|
// Zero out the buffer
|
||||||
|
BOOT_SECTOR_BUFFER[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load the boot sector
|
||||||
|
DEBUG("boot_from_bdev: trying to read boot sector");
|
||||||
|
short result = bdev_read(device, 0, BOOT_SECTOR_BUFFER, 512);
|
||||||
|
if (result > 0) {
|
||||||
|
// Check to see if it's bootable
|
||||||
|
bootable = is_bootable(BOOT_SECTOR_BUFFER, device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bootable) {
|
||||||
|
DEBUG("boot_from_bdev: boot sector is bootable, trying to run");
|
||||||
|
// If bootable, run it
|
||||||
|
boot_sector_run(device);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
DEBUG("boot_from_bdev: boot sector not bootable");
|
||||||
|
// If not bootable...
|
||||||
|
|
||||||
|
// Get the screen for the CLI
|
||||||
|
short cli_screen = cli_txt_screen_get();
|
||||||
|
|
||||||
|
if (device >= 0) {
|
||||||
|
DEBUG("Execute startup file on boot device (if present)");
|
||||||
|
switch (device) {
|
||||||
|
case BDEV_SDC:
|
||||||
|
strcpy(initial_path, "/sd");
|
||||||
|
if (cli_exec_batch(cli_screen, MCP_INIT_SDC) != 0) {
|
||||||
|
cli_exec_batch(cli_screen, MCP_INIT_HDC);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BDEV_FDC:
|
||||||
|
strcpy(initial_path, "/fd");
|
||||||
|
if (cli_exec_batch(cli_screen, MCP_INIT_FDC) != 0) {
|
||||||
|
cli_exec_batch(cli_screen, MCP_INIT_HDC);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BDEV_HDC:
|
||||||
|
strcpy(initial_path, "/hd");
|
||||||
|
cli_exec_batch(cli_screen, MCP_INIT_HDC);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start up the command shell
|
||||||
|
cli_start_repl(cli_screen, initial_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char boot_from_file_sector[] = {
|
||||||
|
0x60, 0x00, 0x00, 0x06, // bra.w boot
|
||||||
|
CPU_M68000, 0x00, 0xf0, 0xe1, // dc.b CPU_M68000, 0, 0xf0, 0xe1
|
||||||
|
0x30, 0x3c, 0x00, 0x40, // boot: move.w #$40,d0
|
||||||
|
0x43, 0xfa, 0x00, 0x0e, // lea (path,pc),a1
|
||||||
|
0x22, 0x09, // move.l a1,d1
|
||||||
|
0x42, 0x82, // clr.l d2
|
||||||
|
0x42, 0x83, // clr.l d3
|
||||||
|
0x4e, 0x4f, // trap #15
|
||||||
|
0x4e, 0x71, // bootloop nop
|
||||||
|
0x60, 0xfc // bra bootloop
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the indicated drive non booting by erasing the boot information
|
||||||
|
*
|
||||||
|
* @param device the number of the block device to use for booting (-1 to go straight to CLI)
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
short boot_non_booting(short device) {
|
||||||
|
unsigned char * buffer;
|
||||||
|
short result = 0;
|
||||||
|
|
||||||
|
buffer = (unsigned char *)malloc(FSYS_SECTOR_SZ);
|
||||||
|
if (buffer != 0) {
|
||||||
|
// Try to read the current sector
|
||||||
|
short n = sys_bdev_read(device, 0, buffer, FSYS_SECTOR_SZ);
|
||||||
|
if (n == FSYS_SECTOR_SZ) {
|
||||||
|
short sector_offset = 0;
|
||||||
|
|
||||||
|
if (device == BDEV_FDC) {
|
||||||
|
// Point to the beginning of the boot code for the FDC (VBR)
|
||||||
|
sector_offset = BOOT_CODE_VBR_OFF;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Point to the beginning of the boot code for the SDC/HDD (MBR)
|
||||||
|
sector_offset = BOOT_CODE_MBR_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boot record read... clear out the boot code
|
||||||
|
for (int i = 0; i < sizeof(boot_from_file_sector); i++) {
|
||||||
|
buffer[sector_offset + i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to write it back
|
||||||
|
n = sys_bdev_write(device, 0, buffer, FSYS_SECTOR_SZ);
|
||||||
|
if (n == FSYS_SECTOR_SZ) {
|
||||||
|
// Success!
|
||||||
|
result = 0;
|
||||||
|
} else {
|
||||||
|
result = DEV_CANNOT_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
result = DEV_CANNOT_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
result = ERR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear up the memory we grabbed...
|
||||||
|
if (buffer) {
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the indicated drive booting from a file
|
||||||
|
*
|
||||||
|
* @param device the number of the block device to use for booting (-1 to go straight to CLI)
|
||||||
|
* @param path the path to the file to boot from
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
short boot_set_file(short device, const char * path) {
|
||||||
|
unsigned char * buffer, x;
|
||||||
|
short result = 0, i = 0;
|
||||||
|
|
||||||
|
buffer = (unsigned char *)malloc(FSYS_SECTOR_SZ);
|
||||||
|
if (buffer != 0) {
|
||||||
|
// Try to read the current sector
|
||||||
|
bdev_init(device);
|
||||||
|
short n = sys_bdev_read(device, 0, buffer, FSYS_SECTOR_SZ);
|
||||||
|
if (n == FSYS_SECTOR_SZ) {
|
||||||
|
int sector_len = sizeof(boot_from_file_sector);
|
||||||
|
int sector_offset = 0;
|
||||||
|
int path_len = strlen(path);
|
||||||
|
|
||||||
|
if (device == BDEV_FDC) {
|
||||||
|
// Set up the floppy disk boot record
|
||||||
|
sector_offset = BOOT_CODE_VBR_OFF;
|
||||||
|
|
||||||
|
// Write 80x86 code to infinite loop at the start of the boot sector
|
||||||
|
// This will help maintain compatibility with MS-DOS and Windows machines
|
||||||
|
buffer[0] = 0xEB;
|
||||||
|
buffer[1] = 0xFF;
|
||||||
|
buffer[2] = 0x90;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Set up the SDC or HDC master boot record
|
||||||
|
sector_offset = BOOT_CODE_MBR_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the boot code over
|
||||||
|
for (i = 0; i < sector_len; i++) {
|
||||||
|
buffer[sector_offset + i] = boot_from_file_sector[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the path
|
||||||
|
for (i = 0; i < path_len; i++) {
|
||||||
|
buffer[sector_offset + i + sector_len] = path[i];
|
||||||
|
}
|
||||||
|
buffer[sector_offset + sector_len + path_len] = 0;
|
||||||
|
|
||||||
|
// Try to write it back
|
||||||
|
n = sys_bdev_write(device, 0, buffer, FSYS_SECTOR_SZ);
|
||||||
|
if (n == FSYS_SECTOR_SZ) {
|
||||||
|
// Success!
|
||||||
|
result = 0;
|
||||||
|
} else {
|
||||||
|
result = DEV_CANNOT_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
result = DEV_CANNOT_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
result = ERR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear up the memory we grabbed...
|
||||||
|
if (buffer) {
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
44
src/boot.h
Normal file
44
src/boot.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
* @file boot.h
|
||||||
|
*
|
||||||
|
* Routines to support the boot process
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BOOT_H
|
||||||
|
#define __BOOT_H
|
||||||
|
|
||||||
|
#define BOOT_DEFAULT -1
|
||||||
|
#define BOOT_SAFE -2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load and display the boot splash screen on the graphics screen
|
||||||
|
*
|
||||||
|
* @return boot device selected by user
|
||||||
|
*/
|
||||||
|
extern short boot_screen();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the boot process after initializing the MCP
|
||||||
|
*
|
||||||
|
* @param device the number of the block device to use for booting (-1 to go straight to CLI)
|
||||||
|
*/
|
||||||
|
extern void boot_from_bdev(short device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the indicated drive non booting by erasing the boot information
|
||||||
|
*
|
||||||
|
* @param device the number of the block device to use for booting (-1 to go straight to CLI)
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
extern short boot_non_booting(short device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the indicated drive booting from a file
|
||||||
|
*
|
||||||
|
* @param device the number of the block device to use for booting (-1 to go straight to CLI)
|
||||||
|
* @param path the path to the file to boot from
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
extern short boot_set_file(short device, const char * path);
|
||||||
|
|
||||||
|
#endif
|
59
src/dev/Makefile
Normal file
59
src/dev/Makefile
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
|
||||||
|
UNIT := C256U_PLUS
|
||||||
|
|
||||||
|
# Define OS-dependent variables
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
RM = del /F/Q
|
||||||
|
else
|
||||||
|
RM = rm -f
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Define model-specific variables, including tools, source files, compiler flags, etc.
|
||||||
|
|
||||||
|
ifeq ($(UNIT),C256U)
|
||||||
|
CC=cc65816
|
||||||
|
AS=as65816
|
||||||
|
AR=nlib
|
||||||
|
|
||||||
|
SRCS_FOR_UNIT=txt_c256.c txt_evid.c indicators_c256.c interrupts_c256.c timers_c256.c
|
||||||
|
CFLAGS_FOR_UNIT=-DMODEL=1 -DCPU=255 --target Foenix --code-model large --data-model large
|
||||||
|
else ifeq ($(UNIT),C256U_PLUS)
|
||||||
|
CC=cc65816
|
||||||
|
AS=as65816
|
||||||
|
AR=nlib
|
||||||
|
|
||||||
|
SRCS_FOR_UNIT=txt_c256.c txt_evid.c indicators_c256.c interrupts_c256.c timers_c256.c
|
||||||
|
CFLAGS_FOR_UNIT=-DMODEL=5 -DCPU=255 --target Foenix --code-model large --data-model large
|
||||||
|
else ifeq ($(UNIT),C256_FMX)
|
||||||
|
CC=cc65816
|
||||||
|
AS=as65816
|
||||||
|
AR=nlib
|
||||||
|
|
||||||
|
SRCS_FOR_UNIT=txt_c256.c txt_evid.c indicators_c256.c interrupts_c256.c timers_c256.c
|
||||||
|
CFLAGS_FOR_UNIT=-DMODEL=0 -DCPU=255 --target Foenix --code-model large --data-model large
|
||||||
|
endif
|
||||||
|
|
||||||
|
INCLUDES=-I.. -I../include
|
||||||
|
CFLAGS=$(INCLUDES) $(CFLAGS_FOR_UNIT) -l
|
||||||
|
ASFLAGS=$(INCLUDES)
|
||||||
|
|
||||||
|
SRCS = bitmap.c block.c channel.c console.c dma.c fsys.c ps2.c sdc.c rtc.c txt_screen.c $(SRCS_FOR_UNIT) # pata.c
|
||||||
|
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||||
|
OBJS4RM = $(subst /,\\,$(OBJS))
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all: devices.a
|
||||||
|
|
||||||
|
# Build the devices library file for this model
|
||||||
|
devices.a: $(OBJS)
|
||||||
|
$(AR) $@ $^
|
||||||
|
|
||||||
|
# Build the object files from C
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
# Clean up after a build
|
||||||
|
clean:
|
||||||
|
$(RM) $(OBJS4RM) devices.a *.lst
|
152
src/dev/bitmap.c
Normal file
152
src/dev/bitmap.c
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/**
|
||||||
|
* @file bitmap.c
|
||||||
|
* @author your name (you@domain.com)
|
||||||
|
* @brief Simple bitmap management code
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-10-02
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "bitmap.h"
|
||||||
|
#include "dma.h"
|
||||||
|
#include "vicky_general.h"
|
||||||
|
|
||||||
|
#define NUM_BITMAP_PLANES 2
|
||||||
|
|
||||||
|
static uint8_t bm_visible = 0; // Track whether a given bitmap plane is visible
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the visibility of a given bitmap plane, and the CLUT to use
|
||||||
|
*
|
||||||
|
* @param plane the number of the bitmap to update
|
||||||
|
* @param clut the number of the CLUT to use for the bitmap
|
||||||
|
* @param is_visible 0 to hide the bitmap, any other number to show it
|
||||||
|
*/
|
||||||
|
void bm_set_visibility(short plane, short clut, short is_visible) {
|
||||||
|
uint8_t new_control_value = (clut & 0x03) << 1 | (is_visible) ? 1 : 0;
|
||||||
|
|
||||||
|
switch(plane) {
|
||||||
|
case 0:
|
||||||
|
*bm0_control = new_control_value;
|
||||||
|
if (is_visible) {
|
||||||
|
bm_visible |= 0x01;
|
||||||
|
} else {
|
||||||
|
bm_visible &= ~0x01;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
*bm1_control = new_control_value;
|
||||||
|
if (is_visible) {
|
||||||
|
bm_visible |= 0x02;
|
||||||
|
} else {
|
||||||
|
bm_visible &= ~0x02;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bm_visible) {
|
||||||
|
tvky_mstr_ctrl->raw = tvky_mstr_ctrl->raw | VKY_MCR_TEXT_OVERLAY | VKY_MCR_GRAPHICS | VKY_MCR_BITMAP;
|
||||||
|
} else {
|
||||||
|
tvky_mstr_ctrl->raw = tvky_mstr_ctrl->raw & ~(VKY_MCR_TEXT_OVERLAY | VKY_MCR_GRAPHICS | VKY_MCR_BITMAP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the
|
||||||
|
*
|
||||||
|
* @param plane the number of the bitmap to set
|
||||||
|
* @param src the address of the bitmap data to use (should be in video RAM)
|
||||||
|
*/
|
||||||
|
void bm_set_data(short plane, uint8_t * src) {
|
||||||
|
uint32_t src_raw = (uint32_t)src - (uint32_t)vram_base;
|
||||||
|
|
||||||
|
switch (plane) {
|
||||||
|
case 0:
|
||||||
|
bm0_address[0] = (uint8_t)(src_raw & 0xff);
|
||||||
|
bm0_address[1] = (uint8_t)((src_raw >> 8) & 0xff);
|
||||||
|
bm0_address[2] = (uint8_t)((src_raw >> 16) & 0xff);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
bm1_address[0] = (uint8_t)(src_raw & 0xff);
|
||||||
|
bm1_address[1] = (uint8_t)((src_raw >> 8) & 0xff);
|
||||||
|
bm1_address[2] = (uint8_t)((src_raw >> 16) & 0xff);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fill the bitmap data with a given color
|
||||||
|
*
|
||||||
|
* @param dest the area of video RAM to fill
|
||||||
|
* @param color the color index to fill it with
|
||||||
|
* @param width the width of the image in pixels
|
||||||
|
* @param height the height of the image in pixels
|
||||||
|
*/
|
||||||
|
void bm_fill(uint8_t * dest, uint8_t color, int width, int height) {
|
||||||
|
vdma_fill_linear(dest, color, (long)width * (long)height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load the color lookup table
|
||||||
|
*
|
||||||
|
* @param clut number of the CLUT to load
|
||||||
|
* @param src pointer to the source data for the CLUT (in B, G, R, A order)
|
||||||
|
*/
|
||||||
|
void bm_load_clut(short clut, uint8_t * src) {
|
||||||
|
uint8_t * base = (uint8_t *)((uint32_t)VKY_GR_CLUT_0 + 4l * 256l * (uint32_t)clut);
|
||||||
|
|
||||||
|
tvky_bg_color->blue = src[0];
|
||||||
|
tvky_bg_color->green = src[1];
|
||||||
|
tvky_bg_color->red = src[2];
|
||||||
|
|
||||||
|
for (int i = 0; i < 4 * 256; i++) {
|
||||||
|
base[i] = src[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load RLE bitmap data into video RAM
|
||||||
|
*
|
||||||
|
* @param dest address to load with the expanded bitmap data (should be in video RAM)
|
||||||
|
* @param src address of the RLE data to expand
|
||||||
|
* @param width the width of the image in pixels
|
||||||
|
* @param height the height of the image in pixels
|
||||||
|
*/
|
||||||
|
void bm_load_rle(uint8_t * dest, uint8_t * src, int width, int height) {
|
||||||
|
uint32_t my_base = (uint32_t)dest;
|
||||||
|
|
||||||
|
// Clear the image map
|
||||||
|
bm_fill(dest, 0, width, height);
|
||||||
|
|
||||||
|
uint8_t count = *(src++);
|
||||||
|
while (count != 0) {
|
||||||
|
uint8_t value = *(src++);
|
||||||
|
if (value != 0) {
|
||||||
|
volatile uint8_t * my_pointer = (uint8_t *)my_base;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
my_pointer[i] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my_base += count;
|
||||||
|
|
||||||
|
count = *(src++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the bitmap system
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void bm_init() {
|
||||||
|
bm_visible = 0;
|
||||||
|
}
|
62
src/dev/bitmap.h
Normal file
62
src/dev/bitmap.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
* @brief Definitions for functions to manage bitmap displays
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BITMAP_H__
|
||||||
|
#define __BITMAP_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the visibility of a given bitmap plane, and the CLUT to use
|
||||||
|
*
|
||||||
|
* @param plane the number of the bitmap to update
|
||||||
|
* @param clut the number of the CLUT to use for the bitmap
|
||||||
|
* @param is_visible 0 to hide the bitmap, any other number to show it
|
||||||
|
*/
|
||||||
|
extern void bm_set_visibility(short plane, short clut, short is_visible);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the
|
||||||
|
*
|
||||||
|
* @param plane the number of the bitmap to set
|
||||||
|
* @param src the address of the bitmap data to use (should be in video RAM)
|
||||||
|
*/
|
||||||
|
extern void bm_set_data(short plane, uint8_t * src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fill the bitmap data with a given color
|
||||||
|
*
|
||||||
|
* @param dest the area of video RAM to fill
|
||||||
|
* @param color the color index to fill it with
|
||||||
|
* @param width the width of the image in pixels
|
||||||
|
* @param height the height of the image in pixels
|
||||||
|
*/
|
||||||
|
extern void bm_fill(uint8_t * dest, uint8_t color, int width, int height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load the color lookup table
|
||||||
|
*
|
||||||
|
* @param clut number of the CLUT to load
|
||||||
|
* @param src pointer to the source data for the CLUT (in B, G, R, A order)
|
||||||
|
*/
|
||||||
|
extern void bm_load_clut(short clut, uint8_t * src);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load RLE bitmap data into video RAM
|
||||||
|
*
|
||||||
|
* @param dest address to load with the expanded bitmap data (should be in video RAM)
|
||||||
|
* @param src address of the RLE data to expand
|
||||||
|
* @param width the width of the image in pixels
|
||||||
|
* @param height the height of the image in pixels
|
||||||
|
*/
|
||||||
|
extern void bm_load_rle(uint8_t * dest, uint8_t * src, int width, int height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the bitmap system
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
extern void bm_init();
|
||||||
|
|
||||||
|
#endif
|
209
src/dev/block.c
Normal file
209
src/dev/block.c
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
/**
|
||||||
|
* Implementation of block device routines
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "log_level.h"
|
||||||
|
#ifndef DEFAULT_LOG_LEVEL
|
||||||
|
#define DEFAULT_LOG_LEVEL LOG_ERROR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "block.h"
|
||||||
|
|
||||||
|
t_dev_block g_block_devs[BDEV_DEVICES_MAX];
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the block driver system
|
||||||
|
//
|
||||||
|
void bdev_init_system() {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
TRACE("bdev_init_system");
|
||||||
|
|
||||||
|
for (i = 0; i < BDEV_DEVICES_MAX; i++) {
|
||||||
|
g_block_devs[i].number = 0;
|
||||||
|
g_block_devs[i].name = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Register a block device driver
|
||||||
|
//
|
||||||
|
SYSTEMCALL short bdev_register(p_dev_block device) {
|
||||||
|
short dev;
|
||||||
|
|
||||||
|
TRACE1("bdev_register(%s)", device->name);
|
||||||
|
|
||||||
|
dev = device->number;
|
||||||
|
if (dev < BDEV_DEVICES_MAX) {
|
||||||
|
// Copy the device description into the master table
|
||||||
|
|
||||||
|
p_dev_block bdev = &g_block_devs[dev];
|
||||||
|
bdev->number = device->number;
|
||||||
|
bdev->name = device->name;
|
||||||
|
bdev->init = device->init;
|
||||||
|
bdev->read = device->read;
|
||||||
|
bdev->write = device->write;
|
||||||
|
bdev->status = device->status;
|
||||||
|
bdev->flush = device->flush;
|
||||||
|
bdev->ioctrl = device->ioctrl;
|
||||||
|
TRACE("bdev_register returning 0");
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
TRACE("bdev_register returning DEV_ERR_BADDEV");
|
||||||
|
return DEV_ERR_BADDEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// dev = the number of the device
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
short bdev_init(short dev) {
|
||||||
|
TRACE1("bdev_init(%d)", (int)dev);
|
||||||
|
|
||||||
|
short ret = DEV_ERR_BADDEV;
|
||||||
|
|
||||||
|
if (dev < BDEV_DEVICES_MAX) {
|
||||||
|
p_dev_block bdev = &g_block_devs[dev];
|
||||||
|
if (bdev->number == dev)
|
||||||
|
ret = bdev->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE1("bdev_init returning %d", (int)ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read a block from the device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// dev = the number of the device
|
||||||
|
// lba = the logical block address of the block to read
|
||||||
|
// buffer = the buffer into which to copy the block data
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of bytes read, any negative number is an error code
|
||||||
|
//
|
||||||
|
SYSTEMCALL short bdev_read(short dev, long lba, unsigned char * buffer, short size) {
|
||||||
|
TRACE4("bdev_read(%d,%ld,%p,%d)", (int)dev, lba, buffer, (int)size);
|
||||||
|
|
||||||
|
short ret = DEV_ERR_BADDEV;
|
||||||
|
|
||||||
|
if (dev < BDEV_DEVICES_MAX) {
|
||||||
|
p_dev_block bdev = &g_block_devs[dev];
|
||||||
|
if (bdev->number == dev)
|
||||||
|
ret = bdev->read(lba, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE1("bdev_read returning %d", (int)ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write a block from the device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// dev = the number of the device
|
||||||
|
// lba = the logical block address of the block to write
|
||||||
|
// buffer = the buffer containing the data to write
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of bytes written, any negative number is an error code
|
||||||
|
//
|
||||||
|
SYSTEMCALL short bdev_write(short dev, long lba, const unsigned char * buffer, short size) {
|
||||||
|
TRACE4("bdev_write(%d,%ld,%p,%d)", (int)dev, lba, buffer, (int)size);
|
||||||
|
|
||||||
|
short ret = DEV_ERR_BADDEV;
|
||||||
|
|
||||||
|
if (dev < BDEV_DEVICES_MAX) {
|
||||||
|
p_dev_block bdev = &g_block_devs[dev];
|
||||||
|
if (bdev->number == dev)
|
||||||
|
ret = bdev->write(lba, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE1("bdev_write returning %d", (int)ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return the status of the block device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// dev = the number of the device
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// the status of the device
|
||||||
|
//
|
||||||
|
SYSTEMCALL short bdev_status(short dev) {
|
||||||
|
TRACE1("bdev_status(%d)", dev);
|
||||||
|
|
||||||
|
short ret = DEV_ERR_BADDEV;
|
||||||
|
|
||||||
|
if (dev < BDEV_DEVICES_MAX) {
|
||||||
|
p_dev_block bdev = &g_block_devs[dev];
|
||||||
|
if (bdev->number == dev)
|
||||||
|
ret = bdev->status();
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE1("bdev_status returning %d", (int)ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ensure that any pending writes to teh device have been completed
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// dev = the number of the device
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
SYSTEMCALL short bdev_flush(short dev) {
|
||||||
|
TRACE1("bdev_flush(%d)", (int)dev);
|
||||||
|
|
||||||
|
short ret = DEV_ERR_BADDEV;
|
||||||
|
|
||||||
|
if (dev < BDEV_DEVICES_MAX) {
|
||||||
|
p_dev_block bdev = &g_block_devs[dev];
|
||||||
|
if (bdev->number == dev)
|
||||||
|
return bdev->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE1("bdev_flush returning %d", (int)ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Issue a control command to the device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// dev = the number of the device
|
||||||
|
// command = the number of the command to send
|
||||||
|
// buffer = pointer to bytes of additional data for the command
|
||||||
|
// size = the size of the buffer
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
SYSTEMCALL short bdev_ioctrl(short dev, short command, unsigned char * buffer, short size) {
|
||||||
|
TRACE4("bdev_ioctrl(%d, %d, %p, %d)", (int)dev, command, buffer, (int)size);
|
||||||
|
|
||||||
|
short ret = DEV_ERR_BADDEV;
|
||||||
|
|
||||||
|
if (dev < BDEV_DEVICES_MAX) {
|
||||||
|
p_dev_block bdev = &g_block_devs[dev];
|
||||||
|
if (bdev->number == dev)
|
||||||
|
ret = bdev->ioctrl(command, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE1("bdev_ioctrl returning %d", (int)ret);
|
||||||
|
return ret;
|
||||||
|
}
|
104
src/dev/block.h
Normal file
104
src/dev/block.h
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/**
|
||||||
|
* Definitions support low level block device drivers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __BLOCK_H
|
||||||
|
#define __BLOCK_H
|
||||||
|
|
||||||
|
#include "errors.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "sys_macros.h"
|
||||||
|
#include "sys_types.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// Preset block device numbers
|
||||||
|
//
|
||||||
|
|
||||||
|
#define BDEV_DEVICES_MAX 8
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the block driver system
|
||||||
|
//
|
||||||
|
extern void bdev_init_system();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Register a block device driver
|
||||||
|
//
|
||||||
|
extern SYSTEMCALL short bdev_register(p_dev_block device);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// dev = the number of the device
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern short bdev_init(short dev);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read a block from the device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// dev = the number of the device
|
||||||
|
// lba = the logical block address of the block to read
|
||||||
|
// buffer = the buffer into which to copy the block data
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of bytes read, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern SYSTEMCALL short bdev_read(short dev, long lba, unsigned char * buffer, short size);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write a block from the device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// dev = the number of the device
|
||||||
|
// lba = the logical block address of the block to write
|
||||||
|
// buffer = the buffer containing the data to write
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of bytes written, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern SYSTEMCALL short bdev_write(short dev, long lba, const unsigned char * buffer, short size);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return the status of the block device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// dev = the number of the device
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// the status of the device
|
||||||
|
//
|
||||||
|
extern SYSTEMCALL short bdev_status(short dev);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ensure that any pending writes to teh device have been completed
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// dev = the number of the device
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern SYSTEMCALL short bdev_flush(short dev);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Issue a control command to the device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// dev = the number of the device
|
||||||
|
// command = the number of the command to send
|
||||||
|
// buffer = pointer to bytes of additional data for the command
|
||||||
|
// size = the size of the buffer
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern SYSTEMCALL short bdev_ioctrl(short dev, short command, unsigned char * buffer, short size);
|
||||||
|
|
||||||
|
#endif
|
215
src/dev/bmp_expand.c
Normal file
215
src/dev/bmp_expand.c
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "vicky_general.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct bmp_color_s {
|
||||||
|
uint8_t red;
|
||||||
|
uint8_t green;
|
||||||
|
uint8_t blue;
|
||||||
|
uint8_t reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bmp_infoheader_s {
|
||||||
|
uint32_t infoheader_size;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
uint16_t planes;
|
||||||
|
uint16_t bit_count;
|
||||||
|
uint32_t compression;
|
||||||
|
uint32_t image_size;
|
||||||
|
uint32_t x_pixels_per_m;
|
||||||
|
uint32_t y_pixels_per_m;
|
||||||
|
uint32_t colors_used;
|
||||||
|
uint32_t colors_important;
|
||||||
|
struct bmp_color_s color_table[];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bmp_header_s {
|
||||||
|
char signature[2];
|
||||||
|
uint32_t file_size;
|
||||||
|
uint32_t reserved;
|
||||||
|
uint32_t offset;
|
||||||
|
struct bmp_infoheader_s info_header;
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint16_t BMP_BC_MONO = 1; // Monochrome
|
||||||
|
const uint16_t BMP_BC_INDEX_16 = 4; // 4-bit indexed color (16 colors total)
|
||||||
|
const uint16_t BMP_BC_INDEX_256 = 8; // 8-bit indexed color (256 colors total)
|
||||||
|
const uint16_t BMP_BC_RGB_16 = 16; // 16-bit RGB
|
||||||
|
const uint16_t BMP_BC_RGB_24 = 24; // 24-bit RGB (True Color)
|
||||||
|
|
||||||
|
const uint32_t BMP_RGB = 0; // No compression
|
||||||
|
const uint32_t BMP_RLE8 = 1; // 8-bit run-length-encoded
|
||||||
|
const uint32_t BMP_RLE4 = 2; // 4-bit run-length-encoded
|
||||||
|
|
||||||
|
const short BMP_OK = 0; // BMP file was processed without error
|
||||||
|
const short BMP_BAD_FILETYPE = -1; // File does not have a BMP signature
|
||||||
|
const short BMP_BAD_FORMAT = -2; // BMP file is not in a supported format (color format or compression)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the components of a color in a graphics color lookup table
|
||||||
|
*
|
||||||
|
* NOTE: this routine might need to be swapped out for different hardware
|
||||||
|
*
|
||||||
|
* @param clut the number of the graphics CLUT to update
|
||||||
|
* @param color the number of the color to update
|
||||||
|
* @param red the red component
|
||||||
|
* @param green the green component
|
||||||
|
* @param blue the blue component
|
||||||
|
*/
|
||||||
|
static void bm_set_color(short clut, short color, uint8_t red, uint8_t green, uint8_t blue) {
|
||||||
|
volatile uint8_t * clut_p = VKY_GR_CLUT_0 + (clut * 256 * 4);
|
||||||
|
uint32_t offset = color * 4;
|
||||||
|
clut_p[offset] = blue;
|
||||||
|
clut_p[offset+1] = green;
|
||||||
|
clut_p[offset+2] = red;
|
||||||
|
clut_p[offset+3] = 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load a color lookup table
|
||||||
|
*
|
||||||
|
* @param src_colors pointer to the BMP color table
|
||||||
|
* @param numcolors the number of colors in the BMP color table
|
||||||
|
* @param clut the number of the color palette to load
|
||||||
|
*/
|
||||||
|
static void load_palette(struct bmp_color_s * src_colors, int numcolors, int clut) {
|
||||||
|
for (int color = 0; color < numcolors; color++) {
|
||||||
|
bm_set_color(clut, color, src_colors[color].red, src_colors[color].green, src_colors[color].blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decompress the BMP 256 color image data, given 8-bit RLE compression
|
||||||
|
*
|
||||||
|
* @param img_data pointer to the BMP compressed image data
|
||||||
|
* @param width the width of the image to build up
|
||||||
|
* @param height the height of the image to build up
|
||||||
|
* @param destination pointer to the destination to expand the image into
|
||||||
|
*/
|
||||||
|
static void expand_index8_rle8(char * img_data, uint32_t width, uint32_t height, char * destination) {
|
||||||
|
int i = 0;
|
||||||
|
uint32_t row = 0;
|
||||||
|
uint32_t column = 0;
|
||||||
|
uint32_t img_index = 0;
|
||||||
|
|
||||||
|
// Calculate address of the first row
|
||||||
|
char * dest_row = (char *)((uint32_t)destination + (height - row - 1) * width);
|
||||||
|
|
||||||
|
// Default the image to color 0
|
||||||
|
memset(destination, 0, width * height);
|
||||||
|
|
||||||
|
// Process the data blocks in the image data until we reach the end of the image
|
||||||
|
while (1) {
|
||||||
|
char count = img_data[img_index++];
|
||||||
|
char value = img_data[img_index++];
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
// We have a run of bytes
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
dest_row[column++] = value;
|
||||||
|
if (column >= width) {
|
||||||
|
column = 0;
|
||||||
|
row -= 1;
|
||||||
|
dest_row = (char *)((uint32_t)destination + (height - row - 1) * width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Count == 0: we have to process the escape sequence
|
||||||
|
switch (value) {
|
||||||
|
case 0:
|
||||||
|
// End of line... handle padding
|
||||||
|
img_index += (3 - img_index % 4);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// End of bitmap... we're done
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// Delta... adjust row and column
|
||||||
|
char dx = img_data[img_index++];
|
||||||
|
char dy = img_data[img_index++];
|
||||||
|
|
||||||
|
row += dy;
|
||||||
|
column += dx;
|
||||||
|
dest_row = (char *)((uint32_t)destination + (height - row - 1) * width);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// value indicates the number of bytes to copy raw
|
||||||
|
for (i = 0; i < value; i++) {
|
||||||
|
char b = img_data[img_index++];
|
||||||
|
dest_row[column++] = b;
|
||||||
|
if (column >= width) {
|
||||||
|
column = 0;
|
||||||
|
row -= 1;
|
||||||
|
dest_row = (char *)((uint32_t)destination + (height - row - 1) * width);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (img_index % 2) {
|
||||||
|
// Skip over padding, if we're on an odd byte
|
||||||
|
img_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BMP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Render a BMP file into a destination bitmap image and a destination color palette
|
||||||
|
*
|
||||||
|
* @param bmp_data pointer to the raw BMP data
|
||||||
|
* @param dest_img pointer to the area in memory to load the expanded bitmap data
|
||||||
|
* @param clut the number of the graphics CLUT to use for the image
|
||||||
|
* @return 0 if image could be processed, any other number is an error
|
||||||
|
*/
|
||||||
|
short bm_bmp_render(char * bmp_data, char * dest_img, short clut) {
|
||||||
|
struct bmp_header_s * bmp_header = (struct bmp_header_s *)bmp_data;
|
||||||
|
if ((bmp_header->signature[0] == 'B') & (bmp_header->signature[0] == 'M')) {
|
||||||
|
// We have a BMP file... calculate the starting address of the image data
|
||||||
|
uint8_t * img_data = (uint8_t *)(bmp_data + bmp_header->offset);
|
||||||
|
|
||||||
|
// Get the statistics on the BMP image
|
||||||
|
uint32_t width = bmp_header->info_header.width;
|
||||||
|
uint32_t height = bmp_header->info_header.height;
|
||||||
|
uint32_t bit_count = bmp_header->info_header.bit_count;
|
||||||
|
uint32_t compression = bmp_header->info_header.compression;
|
||||||
|
|
||||||
|
// Dispatch to the correct expansion routine based on the color mode and the compression
|
||||||
|
switch (bit_count) {
|
||||||
|
case BMP_BC_INDEX_256:
|
||||||
|
switch (compression) {
|
||||||
|
case BMP_RLE8:
|
||||||
|
// 256 color indexed compressed using RLE8
|
||||||
|
load_palette(bmp_header->info_header.color_table, (int)bmp_header->info_header.colors_used, clut);
|
||||||
|
expand_index8_rle8(img_data, width, height, dest_img);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Unsupported compression for 256 color mode
|
||||||
|
return BMP_BAD_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Unsupported color mode
|
||||||
|
return BMP_BAD_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BMP_OK;
|
||||||
|
} else {
|
||||||
|
return BMP_BAD_FILETYPE;
|
||||||
|
}
|
||||||
|
}
|
29
src/dev/bmp_expand.h
Normal file
29
src/dev/bmp_expand.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/**
|
||||||
|
* @file bmp_expand.h
|
||||||
|
* @author your name (you@domain.com)
|
||||||
|
* @brief Provide a way to convert some BMP files to a bitmap image
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2024-06-07
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2024
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __bmp_expand_h__
|
||||||
|
#define __bmp_expand_h__
|
||||||
|
|
||||||
|
extern const short BMP_OK; // BMP file was processed without error
|
||||||
|
extern const short BMP_BAD_FILETYPE; // File does not have a BMP signature
|
||||||
|
extern const short BMP_BAD_FORMAT; // BMP file is not in a supported format (color format or compression)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Render a BMP file into a destination bitmap image and a destination color palette
|
||||||
|
*
|
||||||
|
* @param bmp_data pointer to the raw BMP data
|
||||||
|
* @param dest_img pointer to the area in memory to load the expanded bitmap data
|
||||||
|
* @param clut the number of the graphics CLUT to use for the image
|
||||||
|
* @return 0 if image could be processed, any other number is an error
|
||||||
|
*/
|
||||||
|
extern short bm_bmp_render(char * bmp_data, char * dest_img, short clut);
|
||||||
|
|
||||||
|
#endif
|
545
src/dev/channel.c
Normal file
545
src/dev/channel.c
Normal file
|
@ -0,0 +1,545 @@
|
||||||
|
/**
|
||||||
|
* Implmentation of support low level channel device drivers
|
||||||
|
*
|
||||||
|
* A channel or stream is a sequence of bytes that may be read or written to.
|
||||||
|
*
|
||||||
|
* Examples include: console, serial port, an open file, etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "log_level.h"
|
||||||
|
#ifdef DEFAULT_LOG_LEVEL
|
||||||
|
//#undef DEFAULT_LOG_LEVEL
|
||||||
|
#endif
|
||||||
|
#ifndef DEFAULT_LOG_LEVEL
|
||||||
|
#define DEFAULT_LOG_LEVEL LOG_TRACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "dev/channel.h"
|
||||||
|
#include "errors.h"
|
||||||
|
#include "simpleio.h"
|
||||||
|
#include "sys_types.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
t_dev_chan g_channel_devs[CDEV_DEVICES_MAX];
|
||||||
|
t_channel g_channels[CHAN_MAX];
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the channel driver system
|
||||||
|
//
|
||||||
|
void cdev_init_system() {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
TRACE("cdev_init_system");
|
||||||
|
|
||||||
|
// Clear out all the channel device records...
|
||||||
|
for (i = 0; i < CDEV_DEVICES_MAX; i++) {
|
||||||
|
g_channel_devs[i].number = 0;
|
||||||
|
g_channel_devs[i].name = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear out all the channel records
|
||||||
|
for (i = 0; i < CHAN_MAX; i++) {
|
||||||
|
g_channels[i].number = -1;
|
||||||
|
g_channels[i].dev = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Register a channel device driver
|
||||||
|
//
|
||||||
|
short cdev_register(const p_dev_chan device) {
|
||||||
|
|
||||||
|
TRACE1("cdev_register %s", device->name);
|
||||||
|
short dev;
|
||||||
|
|
||||||
|
dev = device->number;
|
||||||
|
if (dev < CDEV_DEVICES_MAX) {
|
||||||
|
// Copy the device description into the master table
|
||||||
|
memcpy(&g_channel_devs[dev], device, sizeof(t_dev_chan));
|
||||||
|
return E_OK;
|
||||||
|
} else {
|
||||||
|
return DEV_ERR_BADDEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a free channel
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* the device to associate with the channel
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* A pointer to the free channel, 0 if none are available.
|
||||||
|
*/
|
||||||
|
p_channel chan_alloc(short dev) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
TRACE1("chan_alloc(%d)", (int)dev);
|
||||||
|
|
||||||
|
if ((dev >= CDEV_CONSOLE) && (dev < CDEV_FILE)) {
|
||||||
|
/* For most devices (all but files): the channel is always the same number as the device */
|
||||||
|
g_channels[dev].number = dev;
|
||||||
|
g_channels[dev].dev = dev;
|
||||||
|
return &g_channels[dev];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for (i = CDEV_FILE; i < CHAN_MAX; i++) {
|
||||||
|
if (g_channels[i].number != i) {
|
||||||
|
g_channels[i].number = i;
|
||||||
|
g_channels[i].dev = dev;
|
||||||
|
return &g_channels[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return a pointer to the channel record for a given channel handle.
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// c = the number of the channel
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// a pointer to the channel record.
|
||||||
|
//
|
||||||
|
p_channel chan_get_record(short c) {
|
||||||
|
return &g_channels[c];
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return a channel to the pool of unused channels
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// chan = a pointer to the channel record to return to the kernel
|
||||||
|
//
|
||||||
|
void chan_free(p_channel chan) {
|
||||||
|
log_num(LOG_INFO, "chan_free: ", chan->number);
|
||||||
|
|
||||||
|
chan->number = -1;
|
||||||
|
chan->dev = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Find the records for the channel and the channel's device, given the channel number
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// channel = the number of the channel to look up
|
||||||
|
// chan = pointer to the channel structure pointer to set
|
||||||
|
// cdev = pointer to the channel device structure pointer to set
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, a negative number on error
|
||||||
|
//
|
||||||
|
short chan_get_records(short channel, p_channel * chan, p_dev_chan * cdev) {
|
||||||
|
if (channel < CHAN_MAX) {
|
||||||
|
*chan = &g_channels[channel];
|
||||||
|
if ((*chan)->number == channel) {
|
||||||
|
if ((*chan)->dev < CDEV_DEVICES_MAX) {
|
||||||
|
*cdev = &g_channel_devs[(*chan)->dev];
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
log_num(LOG_ERROR, "chan_get_records 1: ", (*chan)->dev);
|
||||||
|
return DEV_ERR_BADDEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log_num(LOG_ERROR, "chan_get_records 2: ", channel);
|
||||||
|
return DEV_ERR_BADDEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return ERR_BADCHANNEL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// dev = the number of the device
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
short cdev_init(short dev) {
|
||||||
|
short ret = DEV_ERR_BADDEV;
|
||||||
|
if (dev < CDEV_DEVICES_MAX) {
|
||||||
|
p_dev_chan cdev = &g_channel_devs[dev];
|
||||||
|
if (cdev->number == dev)
|
||||||
|
ret = cdev->init ? cdev->init() : 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open a channel
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* dev = the device number to have a channel opened
|
||||||
|
* path = a "path" describing how the device is to be open
|
||||||
|
* mode = is the device to be read, written, both?
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the number of the channel opened, negative number on error
|
||||||
|
*/
|
||||||
|
SYSTEMCALL short chan_open(short dev, const uint8_t * path, short mode) {
|
||||||
|
short result;
|
||||||
|
p_channel chan;
|
||||||
|
p_dev_chan cdev;
|
||||||
|
|
||||||
|
TRACE("chan_open");
|
||||||
|
log_num(LOG_DEBUG, "dev = ", dev);
|
||||||
|
|
||||||
|
if (dev < CDEV_DEVICES_MAX) {
|
||||||
|
/* Get the device record */
|
||||||
|
cdev = &g_channel_devs[dev];
|
||||||
|
if (cdev->number != dev) {
|
||||||
|
/* Double check we have a real device */
|
||||||
|
return DEV_ERR_BADDEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grab a channel */
|
||||||
|
chan = chan_alloc(dev);
|
||||||
|
if (chan == 0) {
|
||||||
|
return ERR_OUT_OF_HANDLES;
|
||||||
|
}
|
||||||
|
if (chan->dev != dev) {
|
||||||
|
return ERR_BADCHANNEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open the channel */
|
||||||
|
if (cdev->open) {
|
||||||
|
result = cdev->open(chan, path, mode);
|
||||||
|
if (result == 0) {
|
||||||
|
/* Success: return the channel number */
|
||||||
|
return chan->number;
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// There's no actual open routine... just return the channel number
|
||||||
|
return chan->number;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return DEV_ERR_BADDEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close a channel
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* chan = the number of the channel to close
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* nothing useful
|
||||||
|
*/
|
||||||
|
SYSTEMCALL short chan_close(short channel) {
|
||||||
|
TRACE1("chan_close(%d)", channel);
|
||||||
|
p_channel chan;
|
||||||
|
p_dev_chan cdev;
|
||||||
|
if (chan_get_records(channel, &chan, &cdev) == 0) {
|
||||||
|
if (cdev->close) {
|
||||||
|
cdev->close(chan);
|
||||||
|
}
|
||||||
|
chan_free(chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read bytes from the channel
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// channel = the number of the channel
|
||||||
|
// buffer = the buffer into which to copy the channel data
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of bytes read, any negative number is an error code
|
||||||
|
//
|
||||||
|
SYSTEMCALL short chan_read(short channel, uint8_t * buffer, short size) {
|
||||||
|
p_channel chan;
|
||||||
|
p_dev_chan cdev;
|
||||||
|
short res;
|
||||||
|
|
||||||
|
TRACE3("chan_read(%d,%p,%d)", (int)channel, buffer, (int)size);
|
||||||
|
|
||||||
|
res = chan_get_records(channel, &chan, &cdev);
|
||||||
|
if (res == 0) {
|
||||||
|
DEBUG1("chan_read: %s", cdev->name);
|
||||||
|
res = cdev->read ? cdev->read(chan, buffer, size) : 0;
|
||||||
|
} else {
|
||||||
|
DEBUG1("Couldn't get channel: %d", (int)res);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read a line from the channel
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// channel = the number of the channel
|
||||||
|
// buffer = the buffer into which to copy the channel data
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of bytes read, any negative number is an error code
|
||||||
|
//
|
||||||
|
SYSTEMCALL short chan_readline(short channel, uint8_t * buffer, short size) {
|
||||||
|
p_channel chan;
|
||||||
|
p_dev_chan cdev;
|
||||||
|
short res;
|
||||||
|
|
||||||
|
res = chan_get_records(channel, &chan, &cdev);
|
||||||
|
if (res == 0) {
|
||||||
|
if (cdev->readline) {
|
||||||
|
return cdev->readline(chan, buffer, size);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read a single uint8_t from the channel
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// channel = the number of the channel
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// the value read (if negative, error)
|
||||||
|
//
|
||||||
|
SYSTEMCALL short chan_read_b(short channel) {
|
||||||
|
p_channel chan;
|
||||||
|
p_dev_chan cdev;
|
||||||
|
short res;
|
||||||
|
|
||||||
|
res = chan_get_records(channel, &chan, &cdev);
|
||||||
|
if (res == 0) {
|
||||||
|
if (cdev->read_b) {
|
||||||
|
return cdev->read_b(chan);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write a bytes to the channel
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// channel = the number of the channel
|
||||||
|
// buffer = the buffer containing the data to write
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of bytes written, any negative number is an error code
|
||||||
|
//
|
||||||
|
SYSTEMCALL short chan_write(short channel, const uint8_t * buffer, short size) {
|
||||||
|
p_channel chan;
|
||||||
|
p_dev_chan cdev;
|
||||||
|
short res;
|
||||||
|
log(LOG_TRACE,"chan_write(%d,%p,%x)", channel, buffer, (int)size);
|
||||||
|
|
||||||
|
res = chan_get_records(channel, &chan, &cdev);
|
||||||
|
if (res == 0)
|
||||||
|
res = cdev->write ? cdev->write(chan, buffer, size) : 0;
|
||||||
|
else
|
||||||
|
ERROR1("chan_write error: %d", res);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write a single uint8_t to the device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// channel = the number of the channel
|
||||||
|
// b = the uint8_t to write
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, a negative value on error
|
||||||
|
//
|
||||||
|
SYSTEMCALL short chan_write_b(short channel, uint8_t b) {
|
||||||
|
p_channel chan;
|
||||||
|
p_dev_chan cdev;
|
||||||
|
short res;
|
||||||
|
|
||||||
|
// TRACE("chan_write_b");
|
||||||
|
res = chan_get_records(channel, &chan, &cdev);
|
||||||
|
if (res == 0)
|
||||||
|
res = cdev->write_b ? cdev->write_b(chan, b) : 0;
|
||||||
|
else
|
||||||
|
ERROR1("chan_write_b error: %d", res);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return the status of the channel device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// channel = the number of the channel
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// the status of the device
|
||||||
|
//
|
||||||
|
SYSTEMCALL short chan_status(short channel) {
|
||||||
|
p_channel chan;
|
||||||
|
p_dev_chan cdev;
|
||||||
|
short res;
|
||||||
|
|
||||||
|
res = chan_get_records(channel, &chan, &cdev);
|
||||||
|
if (res == 0)
|
||||||
|
res = cdev->status ? cdev->status(chan) : 0;
|
||||||
|
else
|
||||||
|
ERROR1("chan_status error: %d", res);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ensure that any pending writes to teh device have been completed
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// channel = the number of the channel
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
SYSTEMCALL short chan_flush(short channel) {
|
||||||
|
p_channel chan;
|
||||||
|
p_dev_chan cdev;
|
||||||
|
short res;
|
||||||
|
|
||||||
|
res = chan_get_records(channel, &chan, &cdev);
|
||||||
|
if (res == 0)
|
||||||
|
res = cdev->flush ? cdev->flush(chan) : 0;
|
||||||
|
else
|
||||||
|
ERROR1("flush error: %d", res);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attempt to set the position of the channel cursor (if supported)
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* channel = the number of the channel
|
||||||
|
* position = the position of the cursor
|
||||||
|
* base = whether the position is from the beginning of the channel, relative to the current position,
|
||||||
|
* or relative to the end of the channel
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 = success, a negative number is an error.
|
||||||
|
*/
|
||||||
|
SYSTEMCALL short chan_seek(short channel, long position, short base) {
|
||||||
|
p_channel chan;
|
||||||
|
p_dev_chan cdev;
|
||||||
|
short res;
|
||||||
|
|
||||||
|
res = chan_get_records(channel, &chan, &cdev);
|
||||||
|
if (res == 0)
|
||||||
|
res = cdev->seek ? cdev->seek(chan, position, base) : 0;
|
||||||
|
else
|
||||||
|
ERROR1("chan_seek error: %d", res);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Issue a control command to the device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// channel = the number of the channel
|
||||||
|
// command = the number of the command to send
|
||||||
|
// buffer = pointer to bytes of additional data for the command
|
||||||
|
// size = the size of the buffer
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
SYSTEMCALL short chan_ioctrl(short channel, short command, uint8_t * buffer, short size) {
|
||||||
|
p_channel chan;
|
||||||
|
p_dev_chan cdev;
|
||||||
|
short res;
|
||||||
|
|
||||||
|
res = chan_get_records(channel, &chan, &cdev);
|
||||||
|
if (res == 0)
|
||||||
|
res = cdev->ioctrl ? cdev->ioctrl(chan, command, buffer, size) : 0;
|
||||||
|
else
|
||||||
|
ERROR1("chan_seek error: %d", res);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the device associated with the channel
|
||||||
|
*
|
||||||
|
* @param channel the ID of the channel to query
|
||||||
|
* @return the ID of the device associated with the channel, negative number for error
|
||||||
|
*/
|
||||||
|
short chan_device(short channel) {
|
||||||
|
if (channel >= CHAN_MAX) {
|
||||||
|
// If either channel ID is bad...
|
||||||
|
return ERR_BADCHANNEL;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (g_channels[channel].number != channel) {
|
||||||
|
// Channel is closed
|
||||||
|
return ERR_BADCHANNEL;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return g_channels[channel].dev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap the channel ID assignments for two channels
|
||||||
|
*
|
||||||
|
* Before call: channel1 = "Channel A", channel2 = "Channel B"
|
||||||
|
* After call: channel1 = "Channel B", channel2 = "Channel A"
|
||||||
|
*
|
||||||
|
* @param channel1 the ID of one of the channels
|
||||||
|
* @param channel2 the ID of the other channel
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
short chan_swap(short channel1, short channel2) {
|
||||||
|
if ((channel1 >= CHAN_MAX) || (channel2 >= CHAN_MAX)) {
|
||||||
|
// If either channel ID is bad...
|
||||||
|
return ERR_BADCHANNEL;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
uint8_t tmp_data[CHAN_DATA_SIZE];
|
||||||
|
p_channel chan1 = 0, chan2 = 0;
|
||||||
|
short i = 0, tmp_dev = 0;
|
||||||
|
|
||||||
|
chan1 = &g_channels[channel1];
|
||||||
|
chan2 = &g_channels[channel2];
|
||||||
|
|
||||||
|
// Swap the devices
|
||||||
|
tmp_dev = chan1->dev;
|
||||||
|
chan1->dev = chan2->dev;
|
||||||
|
chan2->dev = tmp_dev;
|
||||||
|
|
||||||
|
// Swap the data blocks
|
||||||
|
memcpy(tmp_data, chan1->data, CHAN_DATA_SIZE);
|
||||||
|
memcpy(chan1->data, chan2->data, CHAN_DATA_SIZE);
|
||||||
|
memcpy(chan2->data, tmp_data, CHAN_DATA_SIZE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
285
src/dev/channel.h
Normal file
285
src/dev/channel.h
Normal file
|
@ -0,0 +1,285 @@
|
||||||
|
/**
|
||||||
|
* Definitions support low level channel device drivers
|
||||||
|
*
|
||||||
|
* A channel or stream is a sequence of bytes that may be read or written to.
|
||||||
|
*
|
||||||
|
* Examples include: console, serial port, an open file, etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CHANNEL_H
|
||||||
|
#define __CHANNEL_H
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
#include "sys_macros.h"
|
||||||
|
#include "sys_types.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Preset channel device numbers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CDEV_DEVICES_MAX 8 // The maximum number of channel devices we will support
|
||||||
|
#define CHAN_MAX 16 // The maximum number of open channels we will support
|
||||||
|
#define CHAN_DATA_SIZE 32 // The number of bytes in the channel's data area
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Channel status bits
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CDEV_STAT_EOF 0x01 // The channel has reached the end of the data
|
||||||
|
#define CDEV_STAT_ERROR 0x02 // The channel has encountered some error
|
||||||
|
#define CDEV_STAT_READABLE 0x04 // The channel has data to read (read will not block)
|
||||||
|
#define CDEV_STAT_WRITABLE 0x08 // The channel can accept data (write will not block)
|
||||||
|
|
||||||
|
#define CDEV_SEEK_START 0 /* Seek from the start of the file */
|
||||||
|
#define CDEV_SEEK_RELATIVE 1 /* Seek from the current position */
|
||||||
|
#define CDEV_SEEK_END 2 /* Seek from teh end of the file */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure defining a channel
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct s_channel {
|
||||||
|
short number; // The number of the channel
|
||||||
|
short dev; // The number of the channel's device
|
||||||
|
uint8_t data[CHAN_DATA_SIZE]; // A block of state data that the channel code can use for its own purposes
|
||||||
|
} t_channel, *p_channel;
|
||||||
|
|
||||||
|
typedef short (*FUNC_CBS_2_S)(p_channel, uint8_t *, short);
|
||||||
|
typedef short (*FUNC_C_2_S)(p_channel);
|
||||||
|
typedef short (*FUNC_CcBS_2_S)(p_channel, const uint8_t *, short);
|
||||||
|
typedef short (*FUNC_CB_2_S)(p_channel, uint8_t);
|
||||||
|
typedef short (*FUNC_CLS_2_S)(p_channel, long, short);
|
||||||
|
typedef short (*FUNC_CSBS_2_S)(p_channel, short, uint8_t *, short);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure defining a channel device's functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct s_dev_chan {
|
||||||
|
short number; // The number of the device (assigned by registration)
|
||||||
|
char * name; // The name of the device
|
||||||
|
FUNC_V_2_S init; // short init() -- Initialize the device
|
||||||
|
FUNC_CcBS_2_S open; // short open(t_channel * chan, const uint8_t * path, short mode) -- open a channel for the device
|
||||||
|
FUNC_V_2_S close; // short close(t_channel * chan) -- called when a channel is closed
|
||||||
|
FUNC_CBS_2_S read; // short read(t_channel *, uint8_t * buffer, short size) -- Read a a buffer from the device
|
||||||
|
FUNC_CBS_2_S readline; // short readline(t_channel *, uint8_t * buffer, short size) -- Read a line of text from the device
|
||||||
|
FUNC_C_2_S read_b; // short read_b(t_channel *) -- read a single uint8_t from the device
|
||||||
|
FUNC_CcBS_2_S write; // short write(t_channel *, const uint8_t * buffer, short size) -- Write a buffer to the device
|
||||||
|
FUNC_CB_2_S write_b; // short write_b(t_channel *, const uint8_t b) -- Write a single uint8_t to the device
|
||||||
|
FUNC_C_2_S status; // short status(t_channel *) -- Get the status of the device
|
||||||
|
FUNC_C_2_S flush; // short flush(t_channel *) -- Ensure that any pending writes to teh device have been completed
|
||||||
|
FUNC_CLS_2_S seek; // short cdev_seek(t_channel *, long position, short base) -- attempt to move the "cursor" position in the channel
|
||||||
|
FUNC_CSBS_2_S ioctrl; // short ioctrl(t_channel *, short command, uint8_t * buffer, short size)) -- Issue a control command to the device
|
||||||
|
} t_dev_chan, *p_dev_chan;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the channel driver system
|
||||||
|
*/
|
||||||
|
extern void cdev_init_system();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register a channel device driver
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* p_dev_chan = pointer to the description of the channel device
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short cdev_register(p_dev_chan device);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a free channel
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* the device to associate with the channel
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* A pointer to the free channel, 0 if none are available.
|
||||||
|
*/
|
||||||
|
extern p_channel chan_alloc(short dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return a channel to the pool of unused channels
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* chan = a pointer to the channel record to return to the kernel
|
||||||
|
*/
|
||||||
|
extern void chan_free(p_channel chan);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return a pointer to the channel record for a given channel handle.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* c = the number of the channel
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* a pointer to the channel record.
|
||||||
|
*/
|
||||||
|
extern p_channel chan_get_record(short c);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the device
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* dev = the number of the device
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, any negative number is an error code
|
||||||
|
*/
|
||||||
|
extern short cdev_init(short dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open a channel
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* dev = the device number to have a channel opened
|
||||||
|
* path = a "path" describing how the device is to be open
|
||||||
|
* mode = is the device to be read, written, both?
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the number of the channel opened, negative number on error
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short chan_open(short dev, const uint8_t * path, short mode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close a channel
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* chan = the number of the channel to close
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* nothing useful
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short chan_close(short chan);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read bytes from the channel
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* channel = the number of the channel
|
||||||
|
* buffer = the buffer into which to copy the channel data
|
||||||
|
* size = the size of the buffer.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* number of bytes read, any negative number is an error code
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short chan_read(short channel, uint8_t * buffer, short size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a line from the channel
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* channel = the number of the channel
|
||||||
|
* buffer = the buffer into which to copy the channel data
|
||||||
|
* size = the size of the buffer.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* number of bytes read, any negative number is an error code
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short chan_readline(short channel, uint8_t * buffer, short size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a single uint8_t from the channel
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* channel = the number of the channel
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the value read (if negative, error)
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short chan_read_b(short channel);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write a bytes to the channel
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* channel = the number of the channel
|
||||||
|
* buffer = the buffer containing the data to write
|
||||||
|
* size = the size of the buffer.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* number of bytes written, any negative number is an error code
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short chan_write(short channel, const uint8_t * buffer, short size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write a single uint8_t to the device
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* channel = the number of the channel
|
||||||
|
* b = the uint8_t to write
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, a negative value on error
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short chan_write_b(short channel, uint8_t b);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the status of the channel device
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* channel = the number of the channel
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the status of the device
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short chan_status(short channel);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure that any pending writes to teh device have been completed
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* channel = the number of the channel
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, any negative number is an error code
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short chan_flush(short channel);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attempt to set the position of the channel cursor (if supported)
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* channel = the number of the channel
|
||||||
|
* position = the position of the cursor
|
||||||
|
* base = whether the position is from the beginning of the channel, relative to the current position,
|
||||||
|
* or relative to the end of the channel
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 = success, a negative number is an error.
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short chan_seek(short channel, long position, short base);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Issue a control command to the device
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* channel = the number of the channel
|
||||||
|
* command = the number of the command to send
|
||||||
|
* buffer = pointer to bytes of additional data for the command
|
||||||
|
* size = the size of the buffer
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, any negative number is an error code
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short chan_ioctrl(short channel, short command, uint8_t * buffer, short size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the device associated with the channel
|
||||||
|
*
|
||||||
|
* @param channel the ID of the channel to query
|
||||||
|
* @return the ID of the device associated with the channel, negative number for error
|
||||||
|
*/
|
||||||
|
extern short chan_device(short channel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swap the channel ID assignments for two channels
|
||||||
|
*
|
||||||
|
* Before call: channel1 = "Channel A", channel2 = "Channel B"
|
||||||
|
* After call: channel1 = "Channel B", channel2 = "Channel A"
|
||||||
|
*
|
||||||
|
* @param channel1 the ID of one of the channels
|
||||||
|
* @param channel2 the ID of the other channel
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
extern short chan_swap(short channel1, short channel2);
|
||||||
|
|
||||||
|
#endif
|
832
src/dev/console.c
Normal file
832
src/dev/console.c
Normal file
|
@ -0,0 +1,832 @@
|
||||||
|
/**
|
||||||
|
* Implementation of the console channel device
|
||||||
|
*
|
||||||
|
* The console maps to the main screen and keyboard.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "log_level.h"
|
||||||
|
#ifndef LOG_LEVEL
|
||||||
|
#define LOG_LEVEL LOG_TRACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "features.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "sys_types.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "dev/channel.h"
|
||||||
|
#include "dev/console.h"
|
||||||
|
#include "dev/ps2.h"
|
||||||
|
#include "dev/kbd_mo.h"
|
||||||
|
#include "dev/txt_screen.h"
|
||||||
|
#include "simpleio.h"
|
||||||
|
|
||||||
|
#define ANSI_BUFFER_SIZE 16
|
||||||
|
#define MAX_ANSI_ARGS 10
|
||||||
|
|
||||||
|
#define CON_CTRL_ANSI 0x80 /* Set to enable ANSI escape processing */
|
||||||
|
#define CON_CTRL_ECHO 0x40 /* Set to enable echo of input characters */
|
||||||
|
|
||||||
|
typedef void (*ansi_handler)(p_channel, short, short[]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure to map an ANSI escape sequence pattern to a handler
|
||||||
|
*/
|
||||||
|
typedef struct s_ansi_seq {
|
||||||
|
char code;
|
||||||
|
ansi_handler handler;
|
||||||
|
} t_ansi_seq, *p_ansi_seq;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure to track console state
|
||||||
|
*/
|
||||||
|
typedef struct s_console_data {
|
||||||
|
unsigned char control; /* Control flags for the console: e.g. process ANSI codes */
|
||||||
|
unsigned char ansi_buffer_count; /* Number of characters in the ANSI BUFFER */
|
||||||
|
char ansi_buffer[ANSI_BUFFER_SIZE]; /* Used to keep track of characters in the ANSI escape sequences */
|
||||||
|
char key_buffer; /* Used to peek at keyboard input */
|
||||||
|
} t_console_data, *p_console_data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Forwards
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern void ansi_cuu(p_channel chan, short arg_count, short args[]);
|
||||||
|
extern void ansi_cuf(p_channel chan, short arg_count, short args[]);
|
||||||
|
extern void ansi_cub(p_channel chan, short arg_count, short args[]);
|
||||||
|
extern void ansi_cud(p_channel chan, short arg_count, short args[]);
|
||||||
|
extern void ansi_cup(p_channel chan, short arg_count, short args[]);
|
||||||
|
extern void ansi_cha(p_channel chan, short arg_count, short args[]);
|
||||||
|
extern void ansi_ed(p_channel chan, short arg_count, short args[]);
|
||||||
|
extern void ansi_el(p_channel chan, short arg_count, short args[]);
|
||||||
|
extern void ansi_ich(p_channel chan, short arg_count, short args[]);
|
||||||
|
extern void ansi_dch(p_channel chan, short arg_count, short args[]);
|
||||||
|
extern void ansi_sgr(p_channel chan, short arg_count, short args[]);
|
||||||
|
static short con_flush(p_channel chan);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Console variables and constants
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ANSI escape sequences
|
||||||
|
*/
|
||||||
|
const t_ansi_seq ansi_sequence[] = {
|
||||||
|
{ '@', ansi_ich },
|
||||||
|
{ 'A', ansi_cuu },
|
||||||
|
{ 'B', ansi_cud },
|
||||||
|
{ 'C', ansi_cuf },
|
||||||
|
{ 'D', ansi_cub },
|
||||||
|
{ 'G', ansi_cha },
|
||||||
|
{ 'J', ansi_ed },
|
||||||
|
{ 'K', ansi_el },
|
||||||
|
{ 'P', ansi_dch },
|
||||||
|
{ 'H', ansi_cup },
|
||||||
|
{ 'm', ansi_sgr },
|
||||||
|
{ 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return true if a character is an initial character for an ANSI escape code
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* c = the character to test
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 if the character is not an ANSI initial, 1 if it is
|
||||||
|
*/
|
||||||
|
short ansi_start_code(char c) {
|
||||||
|
switch (c) {
|
||||||
|
case '\x1b':
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find the escape sequence pattern that matches what we've collected.
|
||||||
|
*
|
||||||
|
* If one is found, execute it.
|
||||||
|
* If one is not found, just dump the ANSI buffer
|
||||||
|
*/
|
||||||
|
void ansi_match_pattern(p_channel chan, p_console_data con_data) {
|
||||||
|
char c;
|
||||||
|
short argc = 0;
|
||||||
|
short arg[MAX_ANSI_ARGS];
|
||||||
|
short i, j;
|
||||||
|
|
||||||
|
TRACE("ansi_match_pattern");
|
||||||
|
|
||||||
|
/* Clear out the argument list */
|
||||||
|
for (i = 0; i < MAX_ANSI_ARGS; i++) {
|
||||||
|
arg[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure we have an escape sequence */
|
||||||
|
if ((con_data->ansi_buffer[0] != '\x1b') || (con_data->ansi_buffer[1] != '[')) {
|
||||||
|
/* If not, dump the buffer and return */
|
||||||
|
con_flush(chan);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to assemble the arguments */
|
||||||
|
for (i = 2, argc = 0; i < con_data->ansi_buffer_count - 1; i++) {
|
||||||
|
c = con_data->ansi_buffer[i];
|
||||||
|
if (isdigit(c)) {
|
||||||
|
/* If the character is a digit, add it to the current argument */
|
||||||
|
arg[argc] = arg[argc] * 10 + (c - '0');
|
||||||
|
|
||||||
|
} else if (c == ';') {
|
||||||
|
/* If it's a semi-colon, start the next argument */
|
||||||
|
argc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argc++;
|
||||||
|
|
||||||
|
/* Get the last character... should be the code */
|
||||||
|
c = con_data->ansi_buffer[con_data->ansi_buffer_count - 1];
|
||||||
|
|
||||||
|
/* Try to find the matching escape code */
|
||||||
|
for (i = 0; ansi_sequence[i].code != 0; i++) {
|
||||||
|
if (ansi_sequence[i].code == c) {
|
||||||
|
ansi_handler handler = ansi_sequence[i].handler;
|
||||||
|
if (handler != 0) {
|
||||||
|
/* If we found the handler... call it */
|
||||||
|
handler(chan, argc, arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We got to the end without a match... dump the buffer */
|
||||||
|
con_flush(chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a character to the ANSI buffer... and process when an escape sequence is found
|
||||||
|
*/
|
||||||
|
void ansi_process_c(p_channel chan, p_console_data con_data, char c) {
|
||||||
|
// TRACE("ansi_process_c");
|
||||||
|
|
||||||
|
if (c == '\x1B') {
|
||||||
|
/* Start the escape sequence */
|
||||||
|
con_data->ansi_buffer[0] = c;
|
||||||
|
con_data->ansi_buffer_count = 1;
|
||||||
|
|
||||||
|
} else if (con_data->ansi_buffer_count > 0) {
|
||||||
|
/* We're processing an escape sequence... add the character to the buffer */
|
||||||
|
con_data->ansi_buffer[con_data->ansi_buffer_count++] = c;
|
||||||
|
|
||||||
|
/* Check to see if we just wrote the trigger */
|
||||||
|
if (((c >= '@') && (c <= 'Z')) ||
|
||||||
|
((c >= 'a') && (c <= 'z'))) {
|
||||||
|
ansi_match_pattern(chan, con_data);
|
||||||
|
con_data->ansi_buffer_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Not working on a sequence... so just print it */
|
||||||
|
txt_put(chan->dev, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ANSI Handler: cursor up
|
||||||
|
*/
|
||||||
|
void ansi_cuu(p_channel chan, short arg_count, short args[]) {
|
||||||
|
t_point position;
|
||||||
|
short delta = 1;
|
||||||
|
|
||||||
|
TRACE("ansi_cuu");
|
||||||
|
|
||||||
|
if (arg_count > 0) {
|
||||||
|
delta = args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delta == 0) delta = 1;
|
||||||
|
|
||||||
|
txt_get_xy(chan->dev, &position);
|
||||||
|
position.y -= delta;
|
||||||
|
txt_set_xy(chan->dev, position.x, position.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ANSI Handler: cursor forward
|
||||||
|
*/
|
||||||
|
void ansi_cuf(p_channel chan, short arg_count, short args[]) {
|
||||||
|
t_point position;
|
||||||
|
short delta = 1;
|
||||||
|
|
||||||
|
TRACE("ansi_cuf");
|
||||||
|
|
||||||
|
if (arg_count > 0) {
|
||||||
|
delta = args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delta == 0) delta = 1;
|
||||||
|
|
||||||
|
txt_get_xy(chan->dev, &position);
|
||||||
|
position.x += delta;
|
||||||
|
txt_set_xy(chan->dev, position.x, position.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ANSI Handler: cursor back
|
||||||
|
*/
|
||||||
|
void ansi_cub(p_channel chan, short arg_count, short args[]) {
|
||||||
|
t_point position;
|
||||||
|
short delta = 1;
|
||||||
|
|
||||||
|
TRACE("ansi_cub");
|
||||||
|
|
||||||
|
if (arg_count > 0) {
|
||||||
|
delta = args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delta == 0) delta = 1;
|
||||||
|
|
||||||
|
txt_get_xy(chan->dev, &position);
|
||||||
|
position.x -= delta;
|
||||||
|
txt_set_xy(chan->dev, position.x, position.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ANSI Handler: cursor down
|
||||||
|
*/
|
||||||
|
void ansi_cud(p_channel chan, short arg_count, short args[]) {
|
||||||
|
t_point position;
|
||||||
|
short delta = 1;
|
||||||
|
|
||||||
|
TRACE("ansi_cud");
|
||||||
|
|
||||||
|
if (arg_count > 0) {
|
||||||
|
delta = args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delta == 0) delta = 1;
|
||||||
|
|
||||||
|
txt_get_xy(chan->dev, &position);
|
||||||
|
position.y += delta;
|
||||||
|
txt_set_xy(chan->dev, position.x, position.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ANSI Handler: cursor position
|
||||||
|
*/
|
||||||
|
void ansi_cup(p_channel chan, short arg_count, short args[]) {
|
||||||
|
unsigned short x = 1;
|
||||||
|
unsigned short y = 1;
|
||||||
|
|
||||||
|
TRACE("ansi_cup");
|
||||||
|
|
||||||
|
if (arg_count > 0) {
|
||||||
|
x = args[0];
|
||||||
|
if (arg_count > 1) {
|
||||||
|
y = args[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x == 0) x = 1;
|
||||||
|
if (y == 0) y = 1;
|
||||||
|
|
||||||
|
txt_set_xy(chan->dev, x - 1, y - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ANSI Handler: cursor horizontal absolute
|
||||||
|
*/
|
||||||
|
void ansi_cha(p_channel chan, short arg_count, short args[]) {
|
||||||
|
t_point position;
|
||||||
|
short column = 1;
|
||||||
|
|
||||||
|
TRACE("ansi_cha");
|
||||||
|
|
||||||
|
if (arg_count > 0) {
|
||||||
|
column = args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (column == 0) column = 1;
|
||||||
|
|
||||||
|
txt_get_xy(chan->dev, &position);
|
||||||
|
txt_set_xy(chan->dev, column - 1, position.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ANSI Handler: erase in display
|
||||||
|
*/
|
||||||
|
void ansi_ed(p_channel chan, short arg_count, short args[]) {
|
||||||
|
unsigned short n = 2;
|
||||||
|
|
||||||
|
TRACE("ansi_ed");
|
||||||
|
|
||||||
|
if (arg_count > 0) {
|
||||||
|
n = args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
txt_clear(chan->dev, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ANSI Handler: erase in line
|
||||||
|
*/
|
||||||
|
void ansi_el(p_channel chan, short arg_count, short args[]) {
|
||||||
|
unsigned short n = 2;
|
||||||
|
|
||||||
|
TRACE("ansi_el");
|
||||||
|
|
||||||
|
if (arg_count > 0) {
|
||||||
|
n = args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
txt_clear_line(chan->dev, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ANSI Handler: insert a character
|
||||||
|
*/
|
||||||
|
void ansi_ich(p_channel chan, short arg_count, short args[]) {
|
||||||
|
unsigned short n = 2;
|
||||||
|
|
||||||
|
TRACE("ansi_ich");
|
||||||
|
|
||||||
|
if (arg_count > 0) {
|
||||||
|
n = args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
txt_insert(chan->dev, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ANSI Handler: delete a character
|
||||||
|
*/
|
||||||
|
void ansi_dch(p_channel chan, short arg_count, short args[]) {
|
||||||
|
unsigned short n = 1;
|
||||||
|
|
||||||
|
TRACE("ansi_dch");
|
||||||
|
|
||||||
|
if (arg_count > 0) {
|
||||||
|
n = args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 0) {
|
||||||
|
txt_delete(chan->dev, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set Graphics Rendition
|
||||||
|
*/
|
||||||
|
void ansi_sgr(p_channel chan, short argc, short args[]) {
|
||||||
|
unsigned char foreground = 0, background = 0;
|
||||||
|
short i;
|
||||||
|
|
||||||
|
TRACE("ansi_sgr");
|
||||||
|
|
||||||
|
/* Get the current colors */
|
||||||
|
txt_get_color(chan->dev, &foreground, &background);
|
||||||
|
|
||||||
|
/* Walk through each argument code... */
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
short code = args[i];
|
||||||
|
|
||||||
|
if ((code >= 30) && (code <= 37)) {
|
||||||
|
/* Set foreground color */
|
||||||
|
foreground = code - 30;
|
||||||
|
|
||||||
|
} else if ((code >= 90) && (code <= 97)) {
|
||||||
|
/* Set bright foreground color */
|
||||||
|
foreground = code - 82;
|
||||||
|
|
||||||
|
} else if ((code >= 40) && (code <= 47)) {
|
||||||
|
/* Set background color */
|
||||||
|
background = code - 40;
|
||||||
|
|
||||||
|
} else if ((code >= 100) && (code <= 107)) {
|
||||||
|
/* Set bright background color */
|
||||||
|
background = code - 92;
|
||||||
|
|
||||||
|
} else if ((code == 0) || (code == 2) || (code == 22)) {
|
||||||
|
/* Reset, dim, and normal intensity */
|
||||||
|
foreground = foreground & 0x07;
|
||||||
|
background = background & 0x07;
|
||||||
|
|
||||||
|
} else if (code == 1) {
|
||||||
|
/* Bold intensity */
|
||||||
|
foreground = foreground | 0x08;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the colors */
|
||||||
|
txt_set_color(chan->dev, foreground, background);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the console... nothing needs to happen here
|
||||||
|
//
|
||||||
|
short con_init() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open the consolde device for the given channel
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* chan = the channel record for this console device
|
||||||
|
* path = unused
|
||||||
|
* mode = unused
|
||||||
|
*
|
||||||
|
* Returns
|
||||||
|
* 0 on success, negative number on failure
|
||||||
|
*/
|
||||||
|
short con_open(p_channel chan, const uint8_t * path, short mode) {
|
||||||
|
int i;
|
||||||
|
p_console_data con_data;
|
||||||
|
|
||||||
|
TRACE("con_open");
|
||||||
|
|
||||||
|
/* Initialize the console data for this channel */
|
||||||
|
|
||||||
|
con_data = (p_console_data)&(chan->data);
|
||||||
|
con_data->control = CON_CTRL_ANSI | CON_CTRL_ECHO;
|
||||||
|
con_data->ansi_buffer_count = 0;
|
||||||
|
for (i = 0; i < ANSI_BUFFER_SIZE; i++) {
|
||||||
|
con_data->ansi_buffer[i] = 0;
|
||||||
|
}
|
||||||
|
con_data->key_buffer = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flush the output to the console...
|
||||||
|
*
|
||||||
|
* Really only does something if the console is set to process ANSI escape codes
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static short con_flush(p_channel chan) {
|
||||||
|
int i;
|
||||||
|
p_console_data con_data;
|
||||||
|
|
||||||
|
con_data = (p_console_data)&(chan->data);
|
||||||
|
if (con_data->control & CON_CTRL_ANSI) {
|
||||||
|
for (i = 0; i < con_data->ansi_buffer_count; i++) {
|
||||||
|
txt_put(chan->dev, con_data->ansi_buffer[i]);
|
||||||
|
con_data->ansi_buffer[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
con_data->ansi_buffer_count = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close the console channel... just flush the data
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* chan = the channel record for this console device
|
||||||
|
*/
|
||||||
|
short con_close(p_channel chan) {
|
||||||
|
con_flush(chan);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send a byte to the console screen
|
||||||
|
*/
|
||||||
|
short con_write_b(p_channel chan, uint8_t b) {
|
||||||
|
p_console_data con_data;
|
||||||
|
|
||||||
|
/* Check to see if we need to process ANSI codes */
|
||||||
|
con_data = (p_console_data)&(chan->data);
|
||||||
|
if (con_data->control & CON_CTRL_ANSI) {
|
||||||
|
/* ANSI codes are to be processed */
|
||||||
|
ansi_process_c(chan, con_data, (char)b);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Not processing ANSI codes... just pass it to the text driver */
|
||||||
|
txt_put(chan->dev, (char)b);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attempt to read from the keyboard.
|
||||||
|
*/
|
||||||
|
short con_read_b(p_channel chan) {
|
||||||
|
p_console_data con_data;
|
||||||
|
|
||||||
|
/* Check to see if we need to process ANSI codes */
|
||||||
|
con_data = (p_console_data)&(chan->data);
|
||||||
|
|
||||||
|
char c;
|
||||||
|
do {
|
||||||
|
if (con_data->key_buffer != 0) {
|
||||||
|
c = con_data->key_buffer;
|
||||||
|
con_data->key_buffer = 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K
|
||||||
|
#ifdef KBD_POLLED
|
||||||
|
ps2_mouse_get_packet();
|
||||||
|
c = kbdmo_getc_poll();
|
||||||
|
#else
|
||||||
|
c = kbdmo_getc();
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef KBD_POLLED
|
||||||
|
c = kbd_getc_poll();
|
||||||
|
#else
|
||||||
|
c = kbd_getc();
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (c == 0);
|
||||||
|
|
||||||
|
if ((con_data->control & CON_CTRL_ECHO) != 0) {
|
||||||
|
// Echo the character to the screen
|
||||||
|
con_write_b(chan, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (short)(c & 0x00ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Attempt to read a buffer's worth of bytes from the keyboard
|
||||||
|
//
|
||||||
|
short con_read(p_channel chan, uint8_t * buffer, short size) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
short c = con_read_b(chan);
|
||||||
|
if (c < 0) {
|
||||||
|
return c;
|
||||||
|
} else if (c > 0) {
|
||||||
|
buffer[i] = (uint8_t)(c & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Attempt to read a line of text from the keyboard (stops at buffer size or newline)
|
||||||
|
//
|
||||||
|
// This routine also allows for some basic line editing
|
||||||
|
//
|
||||||
|
short con_readline(p_channel chan, uint8_t * buffer, short size) {
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (i < size - 1) {
|
||||||
|
short c = con_read_b(chan);
|
||||||
|
if (c < 0) {
|
||||||
|
// Return the error, if we got one
|
||||||
|
return c;
|
||||||
|
|
||||||
|
} else if (c > 0) {
|
||||||
|
c = c & 0xff;
|
||||||
|
|
||||||
|
buffer[i] = 0; // By default, we'll have this as the end of string sentinel
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case CHAR_NL:
|
||||||
|
// Newline character, end the string and return the size of the string
|
||||||
|
buffer[i] = 0;
|
||||||
|
return i;
|
||||||
|
|
||||||
|
case CHAR_CR:
|
||||||
|
// Newline character, end the string and return the size of the string
|
||||||
|
buffer[i] = 0;
|
||||||
|
return i;
|
||||||
|
|
||||||
|
case CHAR_BS:
|
||||||
|
// Backspace character, delete the character to the left
|
||||||
|
if (i > 0) {
|
||||||
|
buffer[--i] = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Ordinary character, add it to the buffer
|
||||||
|
buffer[i++] = (char)c;
|
||||||
|
buffer[i] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write a string of bytes to the console.
|
||||||
|
//
|
||||||
|
// Terminates writing bytes at a null.
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// buffer = the string of bytes
|
||||||
|
// size = the number of bytes to write
|
||||||
|
//
|
||||||
|
short con_write(p_channel chan, const uint8_t * buffer, short size) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
TRACE("con_write");
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
char c = (char)buffer[i];
|
||||||
|
if (c == 0) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
con_write_b(chan, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
short con_has_input(p_channel chan) {
|
||||||
|
p_console_data con_data;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
/* Check to see if we need to process ANSI codes */
|
||||||
|
con_data = (p_console_data)&(chan->data);
|
||||||
|
|
||||||
|
if (con_data->key_buffer != 0) {
|
||||||
|
/* If we already peeked and have a character... return true */
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Otherwise, peek at the keyboard to see if there is a valid key */
|
||||||
|
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K
|
||||||
|
#ifdef KBD_POLLED
|
||||||
|
ps2_mouse_get_packet();
|
||||||
|
c = kbdmo_getc_poll();
|
||||||
|
#else
|
||||||
|
c = kbdmo_getc();
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef KBD_POLLED
|
||||||
|
c = kbd_getc_poll();
|
||||||
|
#else
|
||||||
|
c = kbd_getc();
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (c == 0) {
|
||||||
|
/* No: return false */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Yes: save the key we got and return true */
|
||||||
|
con_data->key_buffer = c;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return the status of the console
|
||||||
|
//
|
||||||
|
short con_status(p_channel chan) {
|
||||||
|
short status = CDEV_STAT_WRITABLE; /* The console is always writable */
|
||||||
|
if (con_has_input(chan)) {
|
||||||
|
/* If there is data available, flag that it's readable */
|
||||||
|
status |= CDEV_STAT_READABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// We can't seek on the console... just return 0
|
||||||
|
//
|
||||||
|
short con_seek(p_channel chan, long position, short base) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show or hide the cursor
|
||||||
|
*
|
||||||
|
* @param chan
|
||||||
|
* @param is_visible boolean to indicate if the cursor should be seen (non-zero) or hidden (0)
|
||||||
|
*/
|
||||||
|
short con_set_cursor_visible(p_channel chan, short is_visible) {
|
||||||
|
txt_set_cursor_visible(chan->dev, is_visible);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
short con_ioctrl(p_channel chan, short command, uint8_t * buffer, short size) {
|
||||||
|
p_console_data con_data;
|
||||||
|
|
||||||
|
/* Check to see if we need to process ANSI codes */
|
||||||
|
con_data = (p_console_data)&(chan->data);
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case CON_IOCTRL_ANSI_ON:
|
||||||
|
/* Turn on ANSI interpreting */
|
||||||
|
con_data->control |= CON_CTRL_ANSI;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case CON_IOCTRL_ANSI_OFF:
|
||||||
|
/* Turn off ANSI interpreting */
|
||||||
|
con_data->control &= ~CON_CTRL_ANSI;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case CON_IOCTRL_ECHO_ON:
|
||||||
|
/* Turn on echo interpreting */
|
||||||
|
con_data->control |= CON_CTRL_ECHO;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case CON_IOCTRL_ECHO_OFF:
|
||||||
|
/* Turn off echo */
|
||||||
|
con_data->control &= ~CON_CTRL_ECHO;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case CON_IOCTRL_BREAK:
|
||||||
|
/* Return the result of the BREAK key test */
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K
|
||||||
|
return kbdmo_break();
|
||||||
|
#else
|
||||||
|
/* TODO: flesh this out for the A2560U */
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case CON_IOCTRL_CURS_ON:
|
||||||
|
// Show the cursor
|
||||||
|
return con_set_cursor_visible(chan, 1);
|
||||||
|
|
||||||
|
case CON_IOCTRL_CURS_OFF:
|
||||||
|
// Hide the cursor
|
||||||
|
return con_set_cursor_visible(chan, 0);
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Install the console device driver
|
||||||
|
//
|
||||||
|
short con_install() {
|
||||||
|
short result;
|
||||||
|
t_dev_chan dev;
|
||||||
|
|
||||||
|
dev.name = "CONSOLE";
|
||||||
|
dev.number = CDEV_CONSOLE;
|
||||||
|
dev.init = con_init;
|
||||||
|
dev.open = con_open;
|
||||||
|
dev.close = con_close;
|
||||||
|
dev.read = con_read;
|
||||||
|
dev.readline = con_readline;
|
||||||
|
dev.read_b = con_read_b;
|
||||||
|
dev.write = con_write;
|
||||||
|
dev.write_b = con_write_b;
|
||||||
|
dev.flush = con_flush;
|
||||||
|
dev.seek = con_seek;
|
||||||
|
dev.status = con_status;
|
||||||
|
dev.ioctrl = con_ioctrl;
|
||||||
|
|
||||||
|
result = cdev_register(&dev);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev.name = "EVID";
|
||||||
|
dev.number = CDEV_EVID;
|
||||||
|
dev.init = con_init;
|
||||||
|
dev.open = con_open;
|
||||||
|
dev.close = con_close;
|
||||||
|
dev.read = con_read;
|
||||||
|
dev.readline = con_readline;
|
||||||
|
dev.read_b = con_read_b;
|
||||||
|
dev.write = con_write;
|
||||||
|
dev.write_b = con_write_b;
|
||||||
|
dev.flush = con_flush;
|
||||||
|
dev.seek = con_seek;
|
||||||
|
dev.status = con_status;
|
||||||
|
dev.ioctrl = con_ioctrl;
|
||||||
|
|
||||||
|
result = cdev_register(&dev);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pre-open the console and EVID channels */
|
||||||
|
|
||||||
|
chan_open(CDEV_CONSOLE, 0, 0);
|
||||||
|
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K || MODEL == MODEL_FOENIX_GENX || MODEL == MODEL_FOENIX_A2560X
|
||||||
|
chan_open(CDEV_EVID, 0, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
24
src/dev/console.h
Normal file
24
src/dev/console.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/**
|
||||||
|
* Implementation of the console channel device
|
||||||
|
*
|
||||||
|
* The console maps to the main screen and keyboard.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __CONSOLE_H
|
||||||
|
#define __CONSOLE_H
|
||||||
|
|
||||||
|
#define CON_IOCTRL_ANSI_ON 0x01 /* IOCTRL Command: turn on ANSI terminal codes */
|
||||||
|
#define CON_IOCTRL_ANSI_OFF 0x02 /* IOCTRL Command: turn off ANSI terminal codes */
|
||||||
|
#define CON_IOCTRL_ECHO_ON 0x03 /* IOCTRL Command: turn on echo of input characters */
|
||||||
|
#define CON_IOCTRL_ECHO_OFF 0x04 /* IOCTRL Command: turn off echo of input characters */
|
||||||
|
#define CON_IOCTRL_BREAK 0x05 /* IOCTRL Command: return the status of the keyboard BREAK */
|
||||||
|
#define CON_IOCTRL_CURS_ON 0x06 /* IOCTRL Command: show the cursor */
|
||||||
|
#define CON_IOCTRL_CURS_OFF 0x07 /* IOCTRL Command: hide the cursor */
|
||||||
|
|
||||||
|
//
|
||||||
|
// Install the console device driver
|
||||||
|
//
|
||||||
|
extern short con_install();
|
||||||
|
|
||||||
|
#endif
|
135
src/dev/dma.c
Normal file
135
src/dev/dma.c
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "dma.h"
|
||||||
|
#include "dma_reg.h"
|
||||||
|
#include "vicky_general.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if an address is in the range of video RAM
|
||||||
|
*
|
||||||
|
* @param address the address to check
|
||||||
|
* @return short 0 if it is not in video RAM, 1 if it is in video RAM
|
||||||
|
*/
|
||||||
|
short is_vram(uint8_t * address) {
|
||||||
|
if ((uint32_t)address >= (uint32_t)vram_base) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Wait while the VDMA engine is busy
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void vdma_wait() {
|
||||||
|
while ((*VDMA_STAT & VDMA_STAT_TFR_BUSY) != 0) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fill video memory using a linear VDMA operation
|
||||||
|
*
|
||||||
|
* @param dest the address of memory to fill (must be in video RAM)
|
||||||
|
* @param value the value to put into memory
|
||||||
|
* @param count the number of bytes to fill
|
||||||
|
*/
|
||||||
|
void vdma_fill_linear(uint8_t * dest, uint8_t value, long count) {
|
||||||
|
if (is_vram(dest)) {
|
||||||
|
// We'll just ignore non-vram addresses
|
||||||
|
|
||||||
|
// Make sure any previous transfer is complete
|
||||||
|
vdma_wait();
|
||||||
|
|
||||||
|
*VDMA_CTRL = 0;
|
||||||
|
|
||||||
|
// Set us up for a 1D fill
|
||||||
|
*VDMA_CTRL = VDMA_CTRL_EN | VDMA_CTRL_FILL;
|
||||||
|
|
||||||
|
// Set the fill value
|
||||||
|
*VDMA_FILL_VALUE = value;
|
||||||
|
|
||||||
|
// Set the destination address
|
||||||
|
uint32_t dest_vram_address = (uint32_t)dest - (uint32_t)vram_base;
|
||||||
|
VDMA_DST_ADDR[0] = (uint8_t)(dest_vram_address & 0xff);
|
||||||
|
VDMA_DST_ADDR[1] = (uint8_t)((dest_vram_address >> 8) & 0xff);
|
||||||
|
VDMA_DST_ADDR[2] = (uint8_t)((dest_vram_address >> 16) & 0xff);
|
||||||
|
|
||||||
|
// Set the count
|
||||||
|
VDMA_SIZE[0] = (uint8_t)(count & 0xff);
|
||||||
|
VDMA_SIZE[1] = (uint8_t)((count >> 8) & 0xff);
|
||||||
|
VDMA_SIZE[2] = (uint8_t)((count >> 16) & 0xff);
|
||||||
|
|
||||||
|
// Start the transfer
|
||||||
|
*VDMA_CTRL = VDMA_CTRL_EN | VDMA_CTRL_FILL | VDMA_CTRL_TRF;
|
||||||
|
|
||||||
|
// Wait for completion
|
||||||
|
for (int i = 0; i < 10; i++) ;
|
||||||
|
|
||||||
|
vdma_wait();
|
||||||
|
|
||||||
|
// Turn off the VDMA engine
|
||||||
|
*VDMA_CTRL = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy data to video memory using a linear VDMA operation
|
||||||
|
*
|
||||||
|
* @param dest the address of memory to copy to (must be in video RAM)
|
||||||
|
* @param src the address of memory to copy from (must be in system RAM)
|
||||||
|
* @param count the number of bytes to fill
|
||||||
|
*/
|
||||||
|
void vdma_copy_linear(uint8_t * dest, uint8_t * src, long count) {
|
||||||
|
if (is_vram(dest)) {
|
||||||
|
// We'll just ignore non-vram destinations
|
||||||
|
|
||||||
|
// Make sure any previous transfer is complete
|
||||||
|
vdma_wait();
|
||||||
|
|
||||||
|
*VDMA_CTRL = 0;
|
||||||
|
*SDMA_CTRL = 0;
|
||||||
|
|
||||||
|
uint32_t src_vram_address = (uint32_t)src;
|
||||||
|
uint32_t dest_vram_address = (uint32_t)dest - (uint32_t)vram_base;
|
||||||
|
|
||||||
|
// Set us up for a 1D copy that goes from SRAM to VRAM
|
||||||
|
*VDMA_CTRL = VDMA_CTRL_EN | VDMA_CTRL_SRC_SRAM;
|
||||||
|
*SDMA_CTRL = SDMA_CTRL_EN | 0x10;
|
||||||
|
|
||||||
|
// Set the source address
|
||||||
|
SDMA_SRC_ADDR[0] = (uint8_t)(src_vram_address & 0xff);
|
||||||
|
SDMA_SRC_ADDR[1] = (uint8_t)((src_vram_address >> 8) & 0xff);
|
||||||
|
SDMA_SRC_ADDR[2] = (uint8_t)((src_vram_address >> 16) & 0xff);
|
||||||
|
SDMA_DST_ADDR[0] = 0;
|
||||||
|
SDMA_DST_ADDR[1] = 0;
|
||||||
|
SDMA_DST_ADDR[2] = 0;
|
||||||
|
|
||||||
|
// Set the destination address
|
||||||
|
VDMA_SRC_ADDR[0] = 0;
|
||||||
|
VDMA_SRC_ADDR[1] = 0;
|
||||||
|
VDMA_SRC_ADDR[2] = 0;
|
||||||
|
VDMA_DST_ADDR[0] = (uint8_t)(dest_vram_address & 0xff);
|
||||||
|
VDMA_DST_ADDR[1] = (uint8_t)((dest_vram_address >> 8) & 0xff);
|
||||||
|
VDMA_DST_ADDR[2] = (uint8_t)((dest_vram_address >> 16) & 0xff);
|
||||||
|
|
||||||
|
// Set the count
|
||||||
|
VDMA_SIZE[0] = (uint8_t)(count & 0xff);
|
||||||
|
VDMA_SIZE[1] = (uint8_t)((count >> 8) & 0xff);
|
||||||
|
VDMA_SIZE[2] = (uint8_t)((count >> 16) & 0xff);
|
||||||
|
SDMA_SIZE[0] = (uint8_t)(count & 0xff);
|
||||||
|
SDMA_SIZE[1] = (uint8_t)((count >> 8) & 0xff);
|
||||||
|
SDMA_SIZE[2] = (uint8_t)((count >> 16) & 0xff);
|
||||||
|
|
||||||
|
// Start the transfer
|
||||||
|
*VDMA_CTRL = VDMA_CTRL_EN | VDMA_CTRL_SRC_SRAM | VDMA_CTRL_TRF;
|
||||||
|
*SDMA_CTRL = SDMA_CTRL_EN | 0x10 | SDMA_CTRL_TRF;
|
||||||
|
|
||||||
|
// Wait for completion
|
||||||
|
vdma_wait();
|
||||||
|
|
||||||
|
// Turn off the DMA engine
|
||||||
|
*VDMA_CTRL = 0;
|
||||||
|
*SDMA_CTRL = 0;
|
||||||
|
}
|
||||||
|
}
|
29
src/dev/dma.h
Normal file
29
src/dev/dma.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/**
|
||||||
|
* @brief Definitions for functions to manage DMA transfers
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DMA_H__
|
||||||
|
#define __DMA_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fill video memory using a linear VDMA operation
|
||||||
|
*
|
||||||
|
* @param dest the address of memory to fill (must be in video RAM)
|
||||||
|
* @param value the value to put into memory
|
||||||
|
* @param count the number of bytes to fill
|
||||||
|
*/
|
||||||
|
extern void vdma_fill_linear(uint8_t * dest, uint8_t value, long count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copy data to video memory using a linear VDMA operation
|
||||||
|
*
|
||||||
|
* @param dest the address of memory to copy to (must be in video RAM)
|
||||||
|
* @param src the address of memory to copy from (must be in system RAM)
|
||||||
|
* @param count the number of bytes to fill
|
||||||
|
*/
|
||||||
|
extern void vdma_copy_linear(uint8_t * dest, uint8_t * src, long count);
|
||||||
|
|
||||||
|
#endif
|
86
src/dev/elf.h
Normal file
86
src/dev/elf.h
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#ifndef _ELF_H
|
||||||
|
#define _ELF_H
|
||||||
|
|
||||||
|
#define ET_NONE 0 // No file type
|
||||||
|
#define ET_REL 1 // Relocatable file
|
||||||
|
#define ET_EXEC 2 // Executable file
|
||||||
|
#define ET_DYN 3 // Shared object file
|
||||||
|
#define ET_CORE 4 // Core file
|
||||||
|
#define ET_NUM 5 // Number of defined types
|
||||||
|
#define EM_NONE 0 // No machine
|
||||||
|
#define EM_386 3 // Intel 80386
|
||||||
|
#define EM_68K 4 // Motorola m68k family
|
||||||
|
#define EM_MIPS 8 // MIPS R3000 big-endian
|
||||||
|
#define EM_MIPS_LE 10 // MIPS R3000 little-endian
|
||||||
|
#define EM_PPC 20 // PowerPC
|
||||||
|
#define EM_PPC64 21 // PowerPC 64-bit
|
||||||
|
#define EM_ARM 40 // ARM
|
||||||
|
|
||||||
|
#if defined(__powerpc__)
|
||||||
|
#define CPU_ARCH EM_PPC
|
||||||
|
#elif defined(__powerpc64__)
|
||||||
|
#define CPU_ARCH EM_PPC64
|
||||||
|
#elif defined(__arm__)
|
||||||
|
#define CPU_ARCH EM_ARM
|
||||||
|
#elif defined(__m68k__) || defined(__M68K__)
|
||||||
|
#define CPU_ARCH EM_68K
|
||||||
|
#else
|
||||||
|
#define CPU_ARCH EM_NONE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PT_NULL = 0,
|
||||||
|
PT_LOAD,
|
||||||
|
PT_DYNAMIC,
|
||||||
|
PT_INTERP,
|
||||||
|
PT_NOTE,
|
||||||
|
PT_SHLIB,
|
||||||
|
PT_PHDR,
|
||||||
|
PT_TLS
|
||||||
|
} progtype_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HDATA_NONE = 0,
|
||||||
|
HDATA_LITTLE,
|
||||||
|
HDATA_BIG
|
||||||
|
} endianness_t;
|
||||||
|
|
||||||
|
struct ident_t {
|
||||||
|
unsigned char magic[4];
|
||||||
|
unsigned char class;
|
||||||
|
unsigned char data;
|
||||||
|
unsigned char version;
|
||||||
|
unsigned char osabi;
|
||||||
|
unsigned char abiversion;
|
||||||
|
unsigned char padding[7];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct ident_t ident;
|
||||||
|
unsigned short type;
|
||||||
|
unsigned short machine;
|
||||||
|
unsigned long version;
|
||||||
|
unsigned long entry;
|
||||||
|
unsigned long progOffset;
|
||||||
|
unsigned long shoff;
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned short ehsize;
|
||||||
|
unsigned short progSize;
|
||||||
|
unsigned short progNum;
|
||||||
|
unsigned short shentsize;
|
||||||
|
unsigned short shnum;
|
||||||
|
unsigned short shtrndx;
|
||||||
|
} elf32_header;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned long type;
|
||||||
|
unsigned long offset;
|
||||||
|
unsigned long virtAddr;
|
||||||
|
unsigned long physAddr;
|
||||||
|
unsigned long fileSize;
|
||||||
|
unsigned long memSize;
|
||||||
|
unsigned long flags;
|
||||||
|
unsigned long align;
|
||||||
|
} elf32_program_header;
|
||||||
|
|
||||||
|
#endif
|
1266
src/dev/fdc.c
Normal file
1266
src/dev/fdc.c
Normal file
File diff suppressed because it is too large
Load diff
136
src/dev/fdc.h
Normal file
136
src/dev/fdc.h
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/**
|
||||||
|
* Definitions support low level FDC device driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FDC_H
|
||||||
|
#define __FDC_H
|
||||||
|
|
||||||
|
#include "sys_types.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions for the FDC controller
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FDC_SECTOR_SIZE 512 /* Size of a block on the FDC */
|
||||||
|
#define FDC_MAX_PARAMS 10 /* Maximum number of parameters/result bytes in a transaction */
|
||||||
|
#define FDC_DEFAULT_RETRIES 3 /* Default number of times we'll retry a transaction */
|
||||||
|
|
||||||
|
#define FDC_STAT_NOINIT 0x01 /* FDC has not been initialized */
|
||||||
|
#define FDC_STAT_PRESENT 0x02 /* FD is present */
|
||||||
|
#define FDC_STAT_PROTECTED 0x04 /* FD is write-protected */
|
||||||
|
#define FDC_STAT_MOTOR_ON 0x08 /* FDC spindle motor is on */
|
||||||
|
|
||||||
|
#define FDC_CTRL_MOTOR_ON 0x0001 /* IOCTRL command to start spinning the motor */
|
||||||
|
#define FDC_CTRL_MOTOR_OFF 0x0002 /* IOCTRL command to start spinning the motor */
|
||||||
|
#define FDC_CTRL_CHECK_CHANGE 0x0003 /* IOCTRL command to check to see if the disk has changed */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure to keep track of the information about a transaction with the floppy drive
|
||||||
|
*/
|
||||||
|
typedef struct s_fdc_trans {
|
||||||
|
short retries; /* The number of retries that may be attempted on the transaction */
|
||||||
|
unsigned char command; /* The command code for the transaction */
|
||||||
|
unsigned char parameters[FDC_MAX_PARAMS]; /* The parameters to send as part of the transaction */
|
||||||
|
short parameter_count; /* The number of parameters to send as part of the command */
|
||||||
|
unsigned char results[FDC_MAX_PARAMS]; /* The parameters to send as part of the transaction */
|
||||||
|
short result_count; /* The number of parameters to send as part of the command */
|
||||||
|
unsigned char *data; /* Pointer to the data buffer to read or write to the FDC */
|
||||||
|
short data_count; /* Number of data bytes to transfer */
|
||||||
|
short direction; /* 0 = no data, 1 = data is written to the FDC, 2 = data is read from the FDC */
|
||||||
|
} t_fdc_trans, *p_fdc_trans;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Install the FDC driver
|
||||||
|
*/
|
||||||
|
extern short fdc_install();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the FDC
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, any negative number is an error code
|
||||||
|
*/
|
||||||
|
extern short fdc_init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether to use DMA or polled I/O for exchanging data
|
||||||
|
*
|
||||||
|
* @param dma 0 for polled I/O, anything else for DMA
|
||||||
|
*/
|
||||||
|
extern void fdc_set_dma(short dma);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a block from the FDC
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* lba = the logical block address of the block to read
|
||||||
|
* buffer = the buffer into which to copy the block data
|
||||||
|
* size = the size of the buffer.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* number of bytes read, any negative number is an error code
|
||||||
|
*/
|
||||||
|
extern short fdc_read(long lba, unsigned char * buffer, short size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write a block to the FDC
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* lba = the logical block address of the block to write
|
||||||
|
* buffer = the buffer containing the data to write
|
||||||
|
* size = the size of the buffer.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* number of bytes written, any negative number is an error code
|
||||||
|
*/
|
||||||
|
extern short fdc_write(long lba, const unsigned char * buffer, short size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the status of the FDC
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the status of the device
|
||||||
|
*/
|
||||||
|
extern short fdc_status();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return any error code of the FDC
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the error code of the device
|
||||||
|
*/
|
||||||
|
extern short fdc_error();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure that any pending writes to teh device have been completed
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, any negative number is an error code
|
||||||
|
*/
|
||||||
|
extern short fdc_flush();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Issue a control command to the device
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* command = the number of the command to send
|
||||||
|
* buffer = pointer to bytes of additional data for the command
|
||||||
|
* size = the size of the buffer
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, any negative number is an error code
|
||||||
|
*/
|
||||||
|
extern short fdc_ioctrl(short command, unsigned char * buffer, short size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Move the read/write head to the indicated cylinder
|
||||||
|
*/
|
||||||
|
extern short fdc_seek(unsigned char cylinder);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Recalibrate the read/write head
|
||||||
|
*/
|
||||||
|
extern short fdc_recalibrate();
|
||||||
|
|
||||||
|
#endif
|
1562
src/dev/fsys.c
Normal file
1562
src/dev/fsys.c
Normal file
File diff suppressed because it is too large
Load diff
238
src/dev/fsys.h
Normal file
238
src/dev/fsys.h
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
/**
|
||||||
|
* Kernel calls for file system access
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FSYS_H
|
||||||
|
#define __FSYS_H
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
#include "sys_macros.h"
|
||||||
|
#include "sys_types.h"
|
||||||
|
|
||||||
|
#define DEFAULT_CHUNK_SIZE 256
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the file system
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, negative number on failure.
|
||||||
|
*/
|
||||||
|
extern short fsys_init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to open a file given the path to the file and the mode.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* path = the ASCIIZ string containing the path to the file.
|
||||||
|
* mode = the mode (e.g. r/w/create)
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the channel ID for the open file (negative if error)
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_open(const char * path, short mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close access to a previously open file.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* fd = the channel ID for the file
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, negative number on failure
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_close(short fd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* N.B.: fsys_open returns a channel ID, and fsys_close accepts a channel ID.
|
||||||
|
* read and write access, seek, eof status, etc. will be handled by the channel
|
||||||
|
* calls.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to open a directory for scanning
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* path = the path to the directory to open
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the handle to the directory if >= 0. An error if < 0
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_opendir(const char * path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a previously open directory
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* dir = the directory handle to close
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, negative number on error
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_closedir(short dir);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to read an entry from an open directory
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* dir = the handle of the open directory
|
||||||
|
* file = pointer to the t_file_info structure to fill out.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, negative number on failure
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_readdir(short dir, p_file_info file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a directory given the path and search for the first file matching the pattern.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* path = the path to the directory to search
|
||||||
|
* pattern = the file name pattern to search for
|
||||||
|
* file = pointer to the t_file_info structure to fill out
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the directory handle to use for subsequent calls if >= 0, error if negative
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_findfirst(const char * path, const char * pattern, p_file_info file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a directory given the path and search for the first file matching the pattern.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* dir = the handle to the directory (returned by fsys_findfirst) to search
|
||||||
|
* file = pointer to the t_file_info structure to fill out
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, error if negative
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_findnext(short dir, p_file_info file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if the file is present.
|
||||||
|
* If it is not, return a file not found error.
|
||||||
|
* If it is, populate the file info record
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* path = the path to the file to check
|
||||||
|
* file = pointer to a file info record to fill in, if the file is found.
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_stat(const char * path, p_file_info file);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the label for the drive holding the path
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* path = path to the drive
|
||||||
|
* label = buffer that will hold the label... should be at least 35 bytes
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_getlabel(char * path, char * label);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the label for the drive holding the path
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* drive = drive number
|
||||||
|
* label = buffer that holds the label
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_setlabel(short drive, const char * label);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Format a drive
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* drive = drive number
|
||||||
|
* label = the label to apply to the drive
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_mkfs(short drive, char * label);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a directory
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* path = the path of the directory to create.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, negative number on failure.
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_mkdir(const char * path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a file or directory
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* path = the path of the file or directory to delete.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, negative number on failure.
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_delete(const char * path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename a file or directory
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* old_path = the current path to the file
|
||||||
|
* new_path = the new path for the file
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, negative number on failure.
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_rename(const char * old_path, const char * new_path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the current working directory (and drive)
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* path = the path that should be the new current
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, negative number on failure.
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_set_cwd(const char * path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current working drive and directory
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* path = the buffer in which to store the directory
|
||||||
|
* size = the size of the buffer in bytes
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, negative number on failure.
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_get_cwd(char * path, short size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load a file into memory at the designated destination address.
|
||||||
|
*
|
||||||
|
* If destination = 0, the file must be in a recognized binary format
|
||||||
|
* that specifies its own loading address.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* path = the path to the file to load
|
||||||
|
* destination = the destination address (0 for use file's address)
|
||||||
|
* start = pointer to the long variable to fill with the starting address
|
||||||
|
* (0 if not an executable, any other number if file is executable
|
||||||
|
* with a known starting address)
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, negative number on error
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_load(const char * path, long destination, long * start);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register a file loading routine
|
||||||
|
*
|
||||||
|
* A file loader, takes a channel number to load from and returns a
|
||||||
|
* short that is the status of the load.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* extension = the file extension to map to
|
||||||
|
* loader = pointer to the file load routine to add
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, negative number on error
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short fsys_register_loader(const char * extension, p_file_loader loader);
|
||||||
|
|
||||||
|
#endif
|
62
src/dev/indicators_c256.c
Normal file
62
src/dev/indicators_c256.c
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
* @file indicators_c256.c
|
||||||
|
* @brief Indicator control logic for the C256 line
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-08-30
|
||||||
|
*
|
||||||
|
* Indicators on the C256 include the SD card LED and the power LED. They can be on or off.
|
||||||
|
* An error state will equate to being off. This code also sets the two status LEDs to their
|
||||||
|
* default blinking state.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "indicators.h"
|
||||||
|
#include "gabe_reg.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set an indicator to the given state
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* ind_number = the number of the indicator to change
|
||||||
|
* state = the state the indicator should take (on, off, error)
|
||||||
|
*/
|
||||||
|
void ind_set(short ind_number, short state) {
|
||||||
|
uint8_t bit = 0;
|
||||||
|
|
||||||
|
// Figure out which bit to manipulate
|
||||||
|
switch (ind_number) {
|
||||||
|
case IND_POWER:
|
||||||
|
bit = GABE_CTRL_PWR_LED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IND_SDC:
|
||||||
|
bit = GABE_CTRL_SDC_LED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Any other indicator is ignored
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == IND_ON) {
|
||||||
|
// Flip the bit on
|
||||||
|
*GABE_MSTR_CTRL |= bit;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Flip the bit off
|
||||||
|
*GABE_MSTR_CTRL &= ~bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the indicators
|
||||||
|
*
|
||||||
|
* Generally, this means the indicators will all be turned off
|
||||||
|
*/
|
||||||
|
void ind_init() {
|
||||||
|
*GABE_MSTR_CTRL = 0;
|
||||||
|
*GABE_LED_FLASH_CTRL = 0x03;
|
||||||
|
|
||||||
|
ind_set(IND_POWER, IND_ON);
|
||||||
|
ind_set(IND_SDC, IND_OFF);
|
||||||
|
}
|
597
src/dev/interrupts_c256.c
Normal file
597
src/dev/interrupts_c256.c
Normal file
|
@ -0,0 +1,597 @@
|
||||||
|
/*
|
||||||
|
* Definitions for the interrupt controls for the C256 machines
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <calypsi/intrinsics65816.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "features.h"
|
||||||
|
#include "interrupt.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
// FoenixMCP interrupt number -> C256 group and mask:
|
||||||
|
|
||||||
|
// INT_SOF_A 0x00 --> 0x00, 0x01 (Main screen start-of-frame)
|
||||||
|
// INT_SOL_A 0x01 --> 0x00, 0x02 (Main screen start-of-line)
|
||||||
|
// INT_VICKY_A_1 0x02 --> 0x01, 0x02 (Sprite Collision)
|
||||||
|
// INT_VICKY_A_2 0x03 --> 0x01, 0x04 (Bitmap Collision)
|
||||||
|
// INT_VICKY_A_3 0x04 --> 0x02, 0x08 (VDMA Interrupt)
|
||||||
|
// INT_VICKY_A_4 0x05 --> 0x02, 0x10 (Tile Collision)
|
||||||
|
// INT_RESERVED_1 0x06 --> 0x02, 0x40 (External Expansion)
|
||||||
|
// INT_VICKY_A_DAC 0x07
|
||||||
|
// INT_SOF_B 0x08
|
||||||
|
// INT_SOL_B 0x09
|
||||||
|
// INT_VICKY_B_1 0x0A
|
||||||
|
// INT_VICKY_B_2 0x0B
|
||||||
|
// INT_VICKY_B_3 0x0C
|
||||||
|
// INT_VICKY_B_4 0x0D
|
||||||
|
// INT_RESERVED_2 0x0E
|
||||||
|
// INT_VICKY_B_DAC 0x0F
|
||||||
|
|
||||||
|
// INT_KBD_PS2 0x10 --> 0x01, 0x01 (PS/2 Keyboard)
|
||||||
|
// INT_KBD_A2560K 0x11
|
||||||
|
// INT_MOUSE 0x12 --> 0x00, 0x80 (PS/2 Mouse)
|
||||||
|
// INT_COM1 0x13 --> 0x01, 0x10 (Serial port 1)
|
||||||
|
// INT_COM2 0x14 --> 0x01, 0x08 (Serial port 2)
|
||||||
|
// INT_LPT1 0x15 --> 0x01, 0x40 (LPT)
|
||||||
|
// INT_FDC 0x16 --> 0x00, 0x40 (Floppy drive)
|
||||||
|
// INT_MIDI 0x17 --> 0x01, 0x20 (MIDI)
|
||||||
|
// INT_TIMER0 0x18 --> 0x00, 0x04 (Timer 0)
|
||||||
|
// INT_TIMER1 0x19 --> 0x00, 0x08 (Timer 1)
|
||||||
|
// INT_TIMER2 0x1A --> 0x00, 0x10 (Timer 2)
|
||||||
|
// INT_TIMER3 0x1B
|
||||||
|
// INT_TIMER4 0x1C
|
||||||
|
// INT_RESERVED_3 0x1D
|
||||||
|
// INT_RESERVED_4 0x1E
|
||||||
|
// INT_RTC 0x1F --> 0x00, 0x20 (Real time clock)
|
||||||
|
|
||||||
|
// INT_PATA 0x20 --> 0x03, 0x04 (IDE)
|
||||||
|
// INT_SDC_INS 0x21 --> 0x02, 0x80 (SDC inserted)
|
||||||
|
// INT_SDC 0x22 --> 0x01, 0x80 (SDC)
|
||||||
|
// INT_OPM_INT 0x23 --> 0x03, 0x02 (OPM)
|
||||||
|
// INT_OPN2_EXT 0x24 --> 0x03, 0x01 (OPN)
|
||||||
|
// INT_OPL3_EXT 0x25 --> 0x02, 0x01 (OPL3)
|
||||||
|
// INT_RESERVED_5 0x26
|
||||||
|
// INT_RESERVED_6 0x27
|
||||||
|
// INT_BEATRIX_0 0x28
|
||||||
|
// INT_BEATRIX_1 0x29
|
||||||
|
// INT_BEATRIX_2 0x2A
|
||||||
|
// INT_BEATRIX_3 0x2B
|
||||||
|
// INT_RESERVED_7 0x2C
|
||||||
|
// INT_DAC1_PB 0x2D /* DAC1 Playback Done (48K) */
|
||||||
|
// INT_RESERVED_8 0x2E /* Reserved */
|
||||||
|
// INT_DAC0_PB 0x2F /* DAC0 Playback Done (44.1K) */
|
||||||
|
|
||||||
|
//
|
||||||
|
// Interrupt Handler Vectors
|
||||||
|
//
|
||||||
|
|
||||||
|
p_int_handler int_handle_00;
|
||||||
|
p_int_handler int_handle_01;
|
||||||
|
p_int_handler int_handle_02;
|
||||||
|
p_int_handler int_handle_03;
|
||||||
|
p_int_handler int_handle_04;
|
||||||
|
p_int_handler int_handle_05;
|
||||||
|
p_int_handler int_handle_06;
|
||||||
|
p_int_handler int_handle_07;
|
||||||
|
|
||||||
|
p_int_handler int_handle_10;
|
||||||
|
p_int_handler int_handle_11;
|
||||||
|
p_int_handler int_handle_12;
|
||||||
|
p_int_handler int_handle_13;
|
||||||
|
p_int_handler int_handle_14;
|
||||||
|
p_int_handler int_handle_15;
|
||||||
|
p_int_handler int_handle_16;
|
||||||
|
p_int_handler int_handle_17;
|
||||||
|
|
||||||
|
p_int_handler int_handle_20;
|
||||||
|
p_int_handler int_handle_21;
|
||||||
|
p_int_handler int_handle_22;
|
||||||
|
p_int_handler int_handle_23;
|
||||||
|
p_int_handler int_handle_24;
|
||||||
|
p_int_handler int_handle_25;
|
||||||
|
p_int_handler int_handle_26;
|
||||||
|
p_int_handler int_handle_27;
|
||||||
|
|
||||||
|
p_int_handler int_handle_30;
|
||||||
|
p_int_handler int_handle_31;
|
||||||
|
p_int_handler int_handle_32;
|
||||||
|
p_int_handler int_handle_33;
|
||||||
|
p_int_handler int_handle_34;
|
||||||
|
p_int_handler int_handle_35;
|
||||||
|
p_int_handler int_handle_36;
|
||||||
|
p_int_handler int_handle_37;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mapping of FoenixMCP interrupt numbers to C256 GABE group numbers (0xff indicates an unassigned interrupt number)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static unsigned short g_int_group[] = {
|
||||||
|
0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0x01, 0xff, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
|
||||||
|
0x03, 0x02, 0x01, 0x03, 0x03, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mapping of FoenixMCP interrupt numbers to C256 GABE mask numbers (0xff indicates an unassigned interrupt number)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static unsigned short g_int_mask[] = {
|
||||||
|
0x01, 0x02, 0x02, 0x04, 0x08, 0x10, 0x40, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0x01, 0xff, 0x80, 0x10, 0x08, 0x40, 0x40, 0x20, 0x04, 0x08, 0x10, 0xff, 0xff, 0xff, 0xff, 0x20,
|
||||||
|
0x04, 0x80, 0x80, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the group number for the interrupt number
|
||||||
|
*/
|
||||||
|
unsigned short int_group(unsigned short n) {
|
||||||
|
return g_int_group[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the mask bit for the interrupt number
|
||||||
|
*/
|
||||||
|
unsigned short int_mask(unsigned short n) {
|
||||||
|
return g_int_mask[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the interrupt registers
|
||||||
|
*/
|
||||||
|
void int_init() {
|
||||||
|
int i;
|
||||||
|
p_int_handler * int_handlers = &int_handle_00;
|
||||||
|
|
||||||
|
// Clear all the interrupt handlers
|
||||||
|
for (i = 0; i < 4 * 8; i++) {
|
||||||
|
int_handlers[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// At Reset, all of those already have those values
|
||||||
|
// the Pol are @ 0x0000 and normally pending are reseted, but it is not impossible that some might be triggered during init
|
||||||
|
|
||||||
|
*EDGE_GRP0 = 0xFF;
|
||||||
|
*EDGE_GRP1 = 0xFF;
|
||||||
|
*EDGE_GRP2 = 0xFF;
|
||||||
|
*EDGE_GRP3 = 0xFF;
|
||||||
|
|
||||||
|
*MASK_GRP0 = 0xFF;
|
||||||
|
*MASK_GRP1 = 0xFF;
|
||||||
|
*MASK_GRP2 = 0xFF;
|
||||||
|
*MASK_GRP3 = 0xFF;
|
||||||
|
|
||||||
|
// Clear all the pending flags
|
||||||
|
|
||||||
|
*PENDING_GRP0 = 0xFF;
|
||||||
|
*PENDING_GRP1 = 0xFF;
|
||||||
|
*PENDING_GRP2 = 0xFF;
|
||||||
|
*PENDING_GRP3 = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable all interrupts
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* a machine dependent representation of the interrupt masking prior to enabling
|
||||||
|
*/
|
||||||
|
SYSTEMCALL short int_enable_all() {
|
||||||
|
// NOTE: this code uses Calypsi specific intrinsic functions
|
||||||
|
// and does a cast that may not be valid
|
||||||
|
|
||||||
|
short status = (short)__get_interrupt_state();
|
||||||
|
__enable_interrupts();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable all interrupts
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* a machine dependent representation of the interrupt masking prior to disabling
|
||||||
|
*/
|
||||||
|
SYSTEMCALL short int_disable_all() {
|
||||||
|
// NOTE: this code uses Calypsi specific intrinsic functions
|
||||||
|
// and does a cast that may not be valid
|
||||||
|
|
||||||
|
short status = (short)__get_interrupt_state();
|
||||||
|
__disable_interrupts();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable an interrupt by masking it
|
||||||
|
*
|
||||||
|
* Interrupt number is made by the group number and number within the group.
|
||||||
|
* For instance, the RTC interrupt would be 0x1F and the Channel A SOF interrupt would be 0x00.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* n = the number of the interrupt: n[7..4] = group number, n[3..0] = individual number.
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void int_disable(unsigned short n) {
|
||||||
|
/* Find the group (the relevant interrupt mask register) for the interrupt */
|
||||||
|
unsigned short group = int_group(n);
|
||||||
|
|
||||||
|
/* Find the mask for the interrupt */
|
||||||
|
unsigned short mask = int_mask(n);
|
||||||
|
|
||||||
|
if ((group != 0xff) && (mask != 0xff)) {
|
||||||
|
// Only set the mask if the mask and group numbers are valid
|
||||||
|
uint8_t new_mask = MASK_GRP0[group] | mask;
|
||||||
|
|
||||||
|
/* Set the mask bit for the interrupt in the correct MASK register */
|
||||||
|
MASK_GRP0[group] = new_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable an interrupt
|
||||||
|
*
|
||||||
|
* Interrupt number is made by the group number and number within the group.
|
||||||
|
* For instance, the RTC interrupt would be 0x1F and the Channel A SOF interrupt would be 0x00.
|
||||||
|
* And interrupt number of 0xFF specifies that all interrupts should be disabled.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* n = the number of the interrupt: n[7..4] = group number, n[3..0] = individual number.
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void int_enable(unsigned short n) {
|
||||||
|
/* Find the group (the relevant interrupt mask register) for the interrupt */
|
||||||
|
unsigned short group = int_group(n);
|
||||||
|
|
||||||
|
/* Find the mask for the interrupt */
|
||||||
|
unsigned short mask = int_mask(n);
|
||||||
|
|
||||||
|
printf("Enable interrupt %d => group: %d, mask: %d\n", n, group, mask);
|
||||||
|
|
||||||
|
if ((group != 0xff) && (mask != 0xff)) {
|
||||||
|
// Only set the mask if the mask and group numbers are valid
|
||||||
|
uint8_t new_mask = MASK_GRP0[group] & ~mask;
|
||||||
|
|
||||||
|
/* Clear the mask bit for the interrupt in the correct MASK register */
|
||||||
|
MASK_GRP0[group] = new_mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert group and mask to an index into a "array" of interrupt handler pointers
|
||||||
|
*
|
||||||
|
* @param group the number of the interrupt's group
|
||||||
|
* @param mask the interupt's mask bit
|
||||||
|
* @return int the offset to the handler (-1 on error)
|
||||||
|
*/
|
||||||
|
static int int_group_mask_to_offset(unsigned short group, unsigned short mask) {
|
||||||
|
if ((group != 0xff) && (mask != 0xff)) {
|
||||||
|
unsigned short position = 0;
|
||||||
|
switch (mask) {
|
||||||
|
case 0x01:
|
||||||
|
position = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x02:
|
||||||
|
position = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x04:
|
||||||
|
position = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x08:
|
||||||
|
position = 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x10:
|
||||||
|
position = 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x20:
|
||||||
|
position = 5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x40:
|
||||||
|
position = 6;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x80:
|
||||||
|
position = 7;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return group * 8 + position;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register a handler for a given interrupt.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* n = the number of the interrupt: n[7..4] = group number, n[3..0] = individual number.
|
||||||
|
* handler = pointer to the interrupt handler to register
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the pointer to the previous interrupt handler
|
||||||
|
*/
|
||||||
|
SYSTEMCALL p_int_handler int_register(unsigned short n, p_int_handler handler) {
|
||||||
|
p_int_handler * handler_ref = 0;
|
||||||
|
p_int_handler old_handler = 0;
|
||||||
|
|
||||||
|
/* Find the group (the relevant interrupt mask register) for the interrupt */
|
||||||
|
unsigned short group = int_group(n);
|
||||||
|
|
||||||
|
/* Find the mask for the interrupt */
|
||||||
|
unsigned short mask = int_mask(n);
|
||||||
|
|
||||||
|
switch(group) {
|
||||||
|
case 0:
|
||||||
|
switch(mask) {
|
||||||
|
case 1:
|
||||||
|
handler_ref = &int_handle_00;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
handler_ref = &int_handle_01;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
handler_ref = &int_handle_02;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
handler_ref = &int_handle_03;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
handler_ref = &int_handle_04;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
handler_ref = &int_handle_05;
|
||||||
|
break;
|
||||||
|
case 64:
|
||||||
|
handler_ref = &int_handle_06;
|
||||||
|
break;
|
||||||
|
case 128:
|
||||||
|
handler_ref = &int_handle_07;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
switch(mask) {
|
||||||
|
case 1:
|
||||||
|
handler_ref = &int_handle_10;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
handler_ref = &int_handle_11;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
handler_ref = &int_handle_12;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
handler_ref = &int_handle_13;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
handler_ref = &int_handle_14;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
handler_ref = &int_handle_15;
|
||||||
|
break;
|
||||||
|
case 64:
|
||||||
|
handler_ref = &int_handle_16;
|
||||||
|
break;
|
||||||
|
case 128:
|
||||||
|
handler_ref = &int_handle_17;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
switch(mask) {
|
||||||
|
case 1:
|
||||||
|
handler_ref = &int_handle_20;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
handler_ref = &int_handle_21;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
handler_ref = &int_handle_22;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
handler_ref = &int_handle_23;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
handler_ref = &int_handle_24;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
handler_ref = &int_handle_25;
|
||||||
|
break;
|
||||||
|
case 64:
|
||||||
|
handler_ref = &int_handle_26;
|
||||||
|
break;
|
||||||
|
case 128:
|
||||||
|
handler_ref = &int_handle_27;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
switch(mask) {
|
||||||
|
case 1:
|
||||||
|
handler_ref = &int_handle_30;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
handler_ref = &int_handle_31;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
handler_ref = &int_handle_32;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
handler_ref = &int_handle_33;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
handler_ref = &int_handle_34;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
handler_ref = &int_handle_35;
|
||||||
|
break;
|
||||||
|
case 64:
|
||||||
|
handler_ref = &int_handle_36;
|
||||||
|
break;
|
||||||
|
case 128:
|
||||||
|
handler_ref = &int_handle_37;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
old_handler = *handler_ref;
|
||||||
|
*handler_ref = handler;
|
||||||
|
|
||||||
|
return old_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return true (non-zero) if an interrupt is pending for the given interrupt
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* n = the number of the interrupt: n[7..4] = group number, n[3..0] = individual number.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* non-zero if interrupt n is pending, 0 if not
|
||||||
|
*/
|
||||||
|
SYSTEMCALL short int_pending(unsigned short n) {
|
||||||
|
/* Find the group (the relevant interrupt mask register) for the interrupt */
|
||||||
|
unsigned short group = int_group(n);
|
||||||
|
|
||||||
|
/* Find the mask for the interrupt */
|
||||||
|
unsigned short mask = int_mask(n);
|
||||||
|
|
||||||
|
if ((group != 0xff) && (mask != 0xff)) {
|
||||||
|
// Only query the pending mask if the mask and group numbers are valid
|
||||||
|
return (PENDING_GRP0[group] & mask);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// If the mask or group number are invalid, just return false
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Acknowledge an interrupt (clear out its pending flag)
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* n = the number of the interrupt: n[7..4] = group number, n[3..0] = individual number.
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void int_clear(unsigned short n) {
|
||||||
|
/* Find the group (the relevant interrupt mask register) for the interrupt */
|
||||||
|
unsigned short group = int_group(n);
|
||||||
|
|
||||||
|
/* Find the mask for the interrupt */
|
||||||
|
unsigned short mask = int_mask(n);
|
||||||
|
|
||||||
|
if ((group != 0xff) && (mask != 0xff)) {
|
||||||
|
// Only set the mask if the mask and group numbers are valid
|
||||||
|
uint8_t new_mask = PENDING_GRP0[group] | mask;
|
||||||
|
|
||||||
|
/* Set the bit for the interrupt to mark it as cleared */
|
||||||
|
PENDING_GRP0[group] = new_mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle incomming IRQ signal
|
||||||
|
*
|
||||||
|
* NOTE: this routine might not be fast enough in C and have to be replaced by hand written
|
||||||
|
* assembly code... but we will try it this way first.
|
||||||
|
*/
|
||||||
|
__attribute__((interrupt(0xffee))) void int_handle_irq() {
|
||||||
|
uint8_t mask_bits = 0;
|
||||||
|
|
||||||
|
// Process any pending interrupts in group 0
|
||||||
|
mask_bits = *PENDING_GRP0;
|
||||||
|
if (mask_bits) {
|
||||||
|
if ((mask_bits & 0x01) && int_handle_00) int_handle_00(); // Start of frame
|
||||||
|
if ((mask_bits & 0x02) && int_handle_01) int_handle_01(); // Start of line
|
||||||
|
if ((mask_bits & 0x04) && int_handle_02) int_handle_02(); // Timer 0
|
||||||
|
if ((mask_bits & 0x08) && int_handle_03) int_handle_03(); // Timer 1
|
||||||
|
if ((mask_bits & 0x10) && int_handle_04) int_handle_04(); // Timer 2
|
||||||
|
if ((mask_bits & 0x20) && int_handle_05) int_handle_05(); // Realtime Clock
|
||||||
|
if ((mask_bits & 0x40) && int_handle_06) int_handle_06(); // Floppy Disk Controller
|
||||||
|
if ((mask_bits & 0x80) && int_handle_07) int_handle_07(); // PS/2 Mouse
|
||||||
|
|
||||||
|
// Clear the pending bits for group 0
|
||||||
|
*PENDING_GRP0 = mask_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process any pending interrupts in group 1
|
||||||
|
mask_bits = *PENDING_GRP1;
|
||||||
|
if (mask_bits) {
|
||||||
|
volatile __attribute__((far)) char * text = (char *)0xafa000;
|
||||||
|
*text = *text + 1;
|
||||||
|
|
||||||
|
if ((mask_bits & 0x01) && int_handle_10) {
|
||||||
|
volatile __attribute__((far)) char * text = (char *)0xafa001;
|
||||||
|
*text = *text + 1;
|
||||||
|
int_handle_10(); // PS/2 Keyboard
|
||||||
|
}
|
||||||
|
if ((mask_bits & 0x02) && int_handle_11) int_handle_11(); // VICKY II Sprite Collision
|
||||||
|
if ((mask_bits & 0x04) && int_handle_12) int_handle_12(); // VICKY II Bitmap Collision
|
||||||
|
if ((mask_bits & 0x08) && int_handle_13) int_handle_13(); // Serial Port #2
|
||||||
|
if ((mask_bits & 0x10) && int_handle_14) int_handle_14(); // Serial Port #1
|
||||||
|
if ((mask_bits & 0x20) && int_handle_15) int_handle_15(); // MIDI Controller
|
||||||
|
if ((mask_bits & 0x40) && int_handle_16) int_handle_16(); // Parallel Port
|
||||||
|
if ((mask_bits & 0x80) && int_handle_17) int_handle_17(); // SD Controller
|
||||||
|
|
||||||
|
// Clear the pending bits for group 1
|
||||||
|
*PENDING_GRP1 = mask_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process any pending interrupts in group 2
|
||||||
|
mask_bits = *PENDING_GRP2;
|
||||||
|
if (mask_bits) {
|
||||||
|
if ((mask_bits & 0x01) && int_handle_20) int_handle_20(); // OPL3
|
||||||
|
// if (mask_bits & 0x02) int_handle_21(); // Currently unused
|
||||||
|
// if (mask_bits & 0x04) int_handle_22(); // Currently unused
|
||||||
|
if ((mask_bits & 0x08) && int_handle_23) int_handle_23(); // VICKY II VDMA
|
||||||
|
if ((mask_bits & 0x10) && int_handle_24) int_handle_24(); // VICKY II Tile Collision
|
||||||
|
// if (mask_bits & 0x20) int_handle_25(); // Currently unused
|
||||||
|
if ((mask_bits & 0x40) && int_handle_26) int_handle_26(); // External Expansion
|
||||||
|
if ((mask_bits & 0x80) && int_handle_27) int_handle_27(); // SD Insert
|
||||||
|
|
||||||
|
// Clear the pending bits for group 2
|
||||||
|
*PENDING_GRP2 = mask_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process any pending interrupts in group 3
|
||||||
|
mask_bits = *PENDING_GRP3;
|
||||||
|
if (mask_bits) {
|
||||||
|
if ((mask_bits & 0x01) && int_handle_30) int_handle_30(); // OPN2
|
||||||
|
if ((mask_bits & 0x02) && int_handle_31) int_handle_31(); // OPM
|
||||||
|
if ((mask_bits & 0x04) && int_handle_32) int_handle_32(); // IDE
|
||||||
|
// // if (mask_bits & 0x08) int_handle_33(); // Currently unused
|
||||||
|
// // if (mask_bits & 0x10) int_handle_34(); // Currently unused
|
||||||
|
// // if (mask_bits & 0x20) int_handle_35(); // Currently unused
|
||||||
|
// // if (mask_bits & 0x40) int_handle_36(); // Currently unused
|
||||||
|
// // if (mask_bits & 0x80) int_handle_37(); // Currently unused
|
||||||
|
|
||||||
|
// Clear the pending bits for group 3
|
||||||
|
*PENDING_GRP3 = mask_bits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle incomming NMI signal
|
||||||
|
*/
|
||||||
|
__attribute__((interrupt(0xffea))) void int_handle_nmi() {
|
||||||
|
}
|
727
src/dev/kbd_mo.c
Normal file
727
src/dev/kbd_mo.c
Normal file
|
@ -0,0 +1,727 @@
|
||||||
|
/*
|
||||||
|
* Declarations for Mo, the built-in keyboard of the A2560K
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "sys_general.h"
|
||||||
|
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "interrupt.h"
|
||||||
|
#include "kbd_mo.h"
|
||||||
|
#include "ring_buffer.h"
|
||||||
|
#include "gabe_reg.h"
|
||||||
|
#include "simpleio.h"
|
||||||
|
|
||||||
|
#define KBD_MO_LEDMATRIX ((volatile unsigned short *)0xFEC01000) /* 6x16 array of 16-bit words: ARGB */
|
||||||
|
#define KBD_MO_LED_ROWS 6
|
||||||
|
#define KBD_MO_LED_COLUMNS 16
|
||||||
|
#define KBD_MO_DATA ((volatile unsigned int *)0xFEC00040) /* Data register for the keyboard (scan codes will be here) */
|
||||||
|
#define KBD_MO_EMPTY 0x8000 /* Status flag that will be set if the keyboard buffer is empty */
|
||||||
|
#define KBD_MO_FULL 0x4000 /* Status flag that will be set if the keyboard buffer is full */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Modifier bit flags
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define KBD_LOCK_SCROLL 0x01
|
||||||
|
#define KBD_LOCK_NUM 0x02
|
||||||
|
#define KBD_LOCK_CAPS 0x04
|
||||||
|
#define KBD_MOD_SHIFT 0x08
|
||||||
|
#define KBD_MOD_ALT 0x10
|
||||||
|
#define KBD_MOD_CTRL 0x20
|
||||||
|
#define KBD_MOD_OS 0x40
|
||||||
|
#define KBD_MOD_MENU 0x80
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Status codes
|
||||||
|
*/
|
||||||
|
#define KBD_STAT_BREAK 0x80 /* BREAK has been pressed recently */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure to track the keyboard input
|
||||||
|
*/
|
||||||
|
struct s_kdbmo_kbd {
|
||||||
|
unsigned char control; /* Bits to control how the keyboard processes things */
|
||||||
|
unsigned char status; /* Status of the keyboard */
|
||||||
|
t_word_ring sc_buf; /* Buffer containing scancodes that have been processed */
|
||||||
|
t_word_ring char_buf; /* Buffer containing characters to be read */
|
||||||
|
unsigned char modifiers; /* State of the modifier keys (CTRL, ALT, SHIFT) and caps lock */
|
||||||
|
|
||||||
|
/* Scan code to character lookup tables */
|
||||||
|
|
||||||
|
char keys_unmodified[128];
|
||||||
|
char keys_shift[128];
|
||||||
|
char keys_control[128];
|
||||||
|
char keys_control_shift[128];
|
||||||
|
char keys_caps[128];
|
||||||
|
char keys_caps_shift[128];
|
||||||
|
char keys_alt[128];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver global variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct s_kdbmo_kbd g_kbdmo_control;
|
||||||
|
static short kbdmo_leds = 0;
|
||||||
|
static unsigned char g_kbdmo_break_sc = 0x2E; // Scancode for the BREAK key (must be pressed with CTRL)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mapping of "codepoints" 0x80 - 0x98 (function keys, etc)
|
||||||
|
* to ANSI escape codes
|
||||||
|
*/
|
||||||
|
const char * ansi_keys[] = {
|
||||||
|
"1", /* HOME */
|
||||||
|
"2", /* INS */
|
||||||
|
"3", /* DELETE */
|
||||||
|
"4", /* END */
|
||||||
|
"5", /* PgUp */
|
||||||
|
"6", /* PgDn */
|
||||||
|
"A", /* Up */
|
||||||
|
"B", /* Left */
|
||||||
|
"C", /* Right */
|
||||||
|
"D", /* Down */
|
||||||
|
"11", /* F1 */
|
||||||
|
"12", /* F2 */
|
||||||
|
"13", /* F3 */
|
||||||
|
"14", /* F4 */
|
||||||
|
"15", /* F5 */
|
||||||
|
"17", /* F6 */
|
||||||
|
"18", /* F7 */
|
||||||
|
"19", /* F8 */
|
||||||
|
"20", /* F9 */
|
||||||
|
"21", /* F10 */
|
||||||
|
"23", /* F11 */
|
||||||
|
"24", /* F12 */
|
||||||
|
"30", /* MONITOR */
|
||||||
|
"31", /* CTX SWITCH */
|
||||||
|
"32" /* MENU HELP */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* US keyboard layout scancode translation tables
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char g_us_kbdmo_layout[] = {
|
||||||
|
// Unmodified
|
||||||
|
0x00, 0x1B, '1', '2', '3', '4', '5', '6', /* 0x00 - 0x07 */
|
||||||
|
'7', '8', '9', '0', '-', '=', 0x08, 0x09, /* 0x08 - 0x0F */
|
||||||
|
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', /* 0x10 - 0x17 */
|
||||||
|
'o', 'p', '[', ']', 0x0D, 0x00, 'a', 's', /* 0x18 - 0x1F */
|
||||||
|
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 0x20 - 0x27 */
|
||||||
|
0x27, '`', 0x00, '\\', 'z', 'x', 'c', 'v', /* 0x28 - 0x2F */
|
||||||
|
'b', 'n', 'm', ',', '.', '/', 0x00, '*', /* 0x30 - 0x37 */
|
||||||
|
0x00, ' ', 0x00, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, /* 0x38 - 0x3F */
|
||||||
|
0x8F, 0x90, 0x91, 0x92, 0x93, 0x00, 0x00, 0x80, /* 0x40 - 0x47 */
|
||||||
|
0x86, 0x84, '-', 0x89, '5', 0x88, '+', 0x83, /* 0x48 - 0x4F */
|
||||||
|
0x87, 0x85, 0x81, 0x82, 0x96, 0x97, 0x98, 0x94, /* 0x50 - 0x57 */
|
||||||
|
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58 - 0x5F */
|
||||||
|
0x00, 0x00, 0x81, 0x80, 0x84, 0x82, 0x83, 0x85, /* 0x60 - 0x67 */
|
||||||
|
0x86, 0x89, 0x87, 0x88, '/', 0x0D, 0x00, 0x00, /* 0x68 - 0x6F */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 - 0x77 */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78 - 0x7F */
|
||||||
|
|
||||||
|
// Shifted
|
||||||
|
0x00, 0x1B, '!', '@', '#', '$', '%', '^', /* 0x00 - 0x07 */
|
||||||
|
'&', '*', '(', ')', '_', '+', 0x08, 0x09, /* 0x08 - 0x0F */
|
||||||
|
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', /* 0x10 - 0x17 */
|
||||||
|
'O', 'P', '{', '}', 0x0A, 0x00, 'A', 'S', /* 0x18 - 0x1F */
|
||||||
|
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', /* 0x20 - 0x27 */
|
||||||
|
0x22, '~', 0x00, '|', 'Z', 'X', 'C', 'V', /* 0x28 - 0x2F */
|
||||||
|
'B', 'N', 'M', '<', '>', '?', 0x00, 0x00, /* 0x30 - 0x37 */
|
||||||
|
0x00, ' ', 0x00, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, /* 0x38 - 0x3F */
|
||||||
|
0x8F, 0x90, 0x91, 0x92, 0x93, 0x00, 0x00, 0x80, /* 0x40 - 0x47 */
|
||||||
|
0x86, 0x84, '-', 0x89, '5', 0x88, '+', 0x83, /* 0x48 - 0x4F */
|
||||||
|
0x87, 0x85, 0x81, 0x82, 0x96, 0x97, 0x98, 0x94, /* 0x50 - 0x57 */
|
||||||
|
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58 - 0x5F */
|
||||||
|
0x00, 0x00, 0x81, 0x80, 0x84, 0x82, 0x83, 0x85, /* 0x60 - 0x67 */
|
||||||
|
0x86, 0x89, 0x87, 0x88, '/', 0x0D, 0x00, 0x00, /* 0x68 - 0x6F */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 - 0x77 */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78 - 0x7F */
|
||||||
|
|
||||||
|
// Control
|
||||||
|
0x00, 0x1B, '1', '2', '3', '4', '5', 0x1E, /* 0x00 - 0x07 */
|
||||||
|
'7', '8', '9', '0', 0x1F, '=', 0x08, 0x09, /* 0x08 - 0x0F */
|
||||||
|
0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x15, 0x09, /* 0x10 - 0x17 */
|
||||||
|
0x0F, 0x10, 0x1B, 0x1D, 0x0A, 0x00, 0x01, 0x13, /* 0x18 - 0x1F */
|
||||||
|
0x04, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, ';', /* 0x20 - 0x27 */
|
||||||
|
0x22, '`', 0x00, '\\', 0x1A, 0x18, 0x03, 0x16, /* 0x28 - 0x2F */
|
||||||
|
0x02, 0x0E, 0x0D, ',', '.', 0x1C, 0x00, 0x00, /* 0x30 - 0x37 */
|
||||||
|
0x00, ' ', 0x00, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, /* 0x38 - 0x3F */
|
||||||
|
0x8F, 0x90, 0x91, 0x92, 0x93, 0x00, 0x00, 0x80, /* 0x40 - 0x47 */
|
||||||
|
0x86, 0x84, '-', 0x89, '5', 0x88, '+', 0x83, /* 0x48 - 0x4F */
|
||||||
|
0x87, 0x85, 0x81, 0x82, 0x96, 0x97, 0x98, 0x94, /* 0x50 - 0x57 */
|
||||||
|
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58 - 0x5F */
|
||||||
|
0x00, 0x00, 0x81, 0x80, 0x84, 0x82, 0x83, 0x85, /* 0x60 - 0x67 */
|
||||||
|
0x86, 0x89, 0x87, 0x88, '/', 0x0D, 0x00, 0x00, /* 0x68 - 0x6F */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 - 0x77 */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78 - 0x7F */
|
||||||
|
|
||||||
|
|
||||||
|
// Control-Shift
|
||||||
|
0x00, 0x1B, '!', '@', '#', '$', '%', '^', /* 0x00 - 0x07 */
|
||||||
|
'&', '*', '(', ')', '_', '+', 0x08, 0x09, /* 0x08 - 0x0F */
|
||||||
|
0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x15, 0x09, /* 0x10 - 0x17 */
|
||||||
|
0x0F, 0x10, 0x1B, 0x1D, 0x0A, 0x00, 0x01, 0x13, /* 0x18 - 0x1F */
|
||||||
|
0x04, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C, ';', /* 0x20 - 0x27 */
|
||||||
|
0x22, '`', 0x00, '\\', 0x1A, 0x18, 0x03, 0x16, /* 0x28 - 0x2F */
|
||||||
|
0x02, 0x0E, 0x0D, ',', '.', 0x1C, 0x00, 0x00, /* 0x30 - 0x37 */
|
||||||
|
0x00, ' ', 0x00, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, /* 0x38 - 0x3F */
|
||||||
|
0x8F, 0x90, 0x91, 0x92, 0x93, 0x00, 0x00, 0x80, /* 0x40 - 0x47 */
|
||||||
|
0x86, 0x84, '-', 0x89, '5', 0x88, '+', 0x83, /* 0x48 - 0x4F */
|
||||||
|
0x87, 0x85, 0x81, 0x82, 0x96, 0x97, 0x98, 0x94, /* 0x50 - 0x57 */
|
||||||
|
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58 - 0x5F */
|
||||||
|
0x00, 0x00, 0x81, 0x80, 0x84, 0x82, 0x83, 0x85, /* 0x60 - 0x67 */
|
||||||
|
0x86, 0x89, 0x87, 0x88, '/', 0x0D, 0x00, 0x00, /* 0x68 - 0x6F */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 - 0x77 */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78 - 0x7F */
|
||||||
|
|
||||||
|
// Capslock
|
||||||
|
0x00, 0x1B, '1', '2', '3', '4', '5', '6', /* 0x00 - 0x07 */
|
||||||
|
'7', '8', '9', '0', '-', '=', 0x08, 0x09, /* 0x08 - 0x0F */
|
||||||
|
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', /* 0x10 - 0x17 */
|
||||||
|
'O', 'P', '[', ']', 0x0D, 0x00, 'A', 'S', /* 0x18 - 0x1F */
|
||||||
|
'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', /* 0x20 - 0x27 */
|
||||||
|
0x27, '`', 0x00, '\\', 'Z', 'X', 'C', 'V', /* 0x28 - 0x2F */
|
||||||
|
'B', 'N', 'M', ',', '.', '/', 0x00, 0x00, /* 0x30 - 0x37 */
|
||||||
|
0x00, ' ', 0x00, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, /* 0x38 - 0x3F */
|
||||||
|
0x8F, 0x90, 0x91, 0x92, 0x93, 0x00, 0x00, '7', /* 0x40 - 0x47 */
|
||||||
|
'8', '9', '-', '4', '5', '6', '+', '1', /* 0x48 - 0x4F */
|
||||||
|
'2', '3', '0', '.', 0x96, 0x97, 0x98, 0x94, /* 0x50 - 0x57 */
|
||||||
|
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58 - 0x5F */
|
||||||
|
0x00, 0x00, 0x81, 0x80, 0x84, 0x82, 0x83, 0x85, /* 0x60 - 0x67 */
|
||||||
|
0x86, 0x89, 0x87, 0x88, '/', 0x0D, 0x00, 0x00, /* 0x68 - 0x6F */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 - 0x77 */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78 - 0x7F */
|
||||||
|
|
||||||
|
// Caps-Shift
|
||||||
|
0x00, 0x1B, '!', '@', '#', '$', '%', '^', /* 0x00 - 0x07 */
|
||||||
|
'&', '*', '(', ')', '_', '+', 0x08, 0x09, /* 0x08 - 0x0F */
|
||||||
|
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', /* 0x10 - 0x17 */
|
||||||
|
'o', 'p', '{', '}', 0x0A, 0x00, 'a', 's', /* 0x18 - 0x1F */
|
||||||
|
'd', 'f', 'g', 'h', 'j', 'k', 'l', ':', /* 0x20 - 0x27 */
|
||||||
|
0x22, '~', 0x00, '|', 'z', 'x', 'c', 'v', /* 0x28 - 0x2F */
|
||||||
|
'b', 'n', 'm', '<', '>', '?', 0x00, 0x00, /* 0x30 - 0x37 */
|
||||||
|
0x00, ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38 - 0x3F */
|
||||||
|
0x8F, 0x90, 0x91, 0x92, 0x93, 0x00, 0x00, '7', /* 0x40 - 0x47 */
|
||||||
|
'8', '9', '-', '4', '5', '6', '+', '1', /* 0x48 - 0x4F */
|
||||||
|
'2', '3', '0', '.', 0x96, 0x97, 0x98, 0x94, /* 0x50 - 0x57 */
|
||||||
|
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58 - 0x5F */
|
||||||
|
0x00, 0x00, 0x81, 0x80, 0x84, 0x82, 0x83, 0x85, /* 0x60 - 0x67 */
|
||||||
|
0x86, 0x89, 0x87, 0x88, '/', 0x0D, 0x00, 0x00, /* 0x68 - 0x6F */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 - 0x77 */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78 - 0x7F */
|
||||||
|
|
||||||
|
// ALT
|
||||||
|
0x00, 0x1B, '1', '2', '3', '4', '5', '6', /* 0x00 - 0x07 */
|
||||||
|
'7', '8', '9', '0', '-', '=', 0x08, 0x09, /* 0x08 - 0x0F */
|
||||||
|
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', /* 0x10 - 0x17 */
|
||||||
|
'o', 'p', '[', ']', 0x0D, 0x00, 'a', 's', /* 0x18 - 0x1F */
|
||||||
|
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 0x20 - 0x27 */
|
||||||
|
0x27, '`', 0x00, '\\', 'z', 'x', 'c', 'v', /* 0x28 - 0x2F */
|
||||||
|
'b', 'n', 'm', ',', '.', '/', 0x00, '*', /* 0x30 - 0x37 */
|
||||||
|
0x00, ' ', 0x00, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, /* 0x38 - 0x3F */
|
||||||
|
0x8F, 0x90, 0x91, 0x92, 0x93, 0x00, 0x00, 0x80, /* 0x40 - 0x47 */
|
||||||
|
0x86, 0x84, '-', 0x89, '5', 0x88, '+', 0x83, /* 0x48 - 0x4F */
|
||||||
|
0x87, 0x85, 0x81, 0x82, 0x96, 0x97, 0x98, 0x94, /* 0x50 - 0x57 */
|
||||||
|
0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58 - 0x5F */
|
||||||
|
0x00, 0x00, 0x81, 0x80, 0x84, 0x82, 0x83, 0x85, /* 0x60 - 0x67 */
|
||||||
|
0x86, 0x89, 0x87, 0x88, '/', 0x0D, 0x00, 0x00, /* 0x68 - 0x6F */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 - 0x77 */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78 - 0x7F */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the color of the A2560K keyboard LED matrix
|
||||||
|
*
|
||||||
|
* @param row the number of the row to set (0 - 5)
|
||||||
|
* @param color the color for the LEDs: ARGB
|
||||||
|
*/
|
||||||
|
void kbdmo_set_led_matrix_row(unsigned char row, unsigned short color) {
|
||||||
|
int column;
|
||||||
|
for (column = 0; column < KBD_MO_LED_COLUMNS; column++) {
|
||||||
|
KBD_MO_LEDMATRIX[row * KBD_MO_LED_COLUMNS + column] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set all the LEDs to the same color
|
||||||
|
*
|
||||||
|
* @param color the color for the LEDs: ARGB
|
||||||
|
*/
|
||||||
|
void kbdmo_set_led_matrix_fill(unsigned short color) {
|
||||||
|
unsigned char row;
|
||||||
|
for (row = 0; row < KBD_MO_LED_ROWS; row++) {
|
||||||
|
kbdmo_set_led_matrix_row(row, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure everything is removed from Mo's input buffer
|
||||||
|
*/
|
||||||
|
void kbdmo_flush_out() {
|
||||||
|
long data;
|
||||||
|
|
||||||
|
TRACE("kbdmo_flush_out");
|
||||||
|
|
||||||
|
/* While there is data in the buffer ... */
|
||||||
|
do {
|
||||||
|
data = *KBD_MO_DATA;
|
||||||
|
} while ((data & 0x00ff0000) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check to see if a BREAK code has been pressed recently
|
||||||
|
* If so, return true and reset the internal flag.
|
||||||
|
*
|
||||||
|
* BREAK will be F-ESC on the A2560K
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* true if a BREAK has been pressed since the last check
|
||||||
|
*/
|
||||||
|
bool kbdmo_break() {
|
||||||
|
if (g_kbdmo_control.status & KBD_STAT_BREAK) {
|
||||||
|
/* BREAK was pressed: clear the flag and return a 1 */
|
||||||
|
g_kbdmo_control.status &= ~KBD_STAT_BREAK;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
/* BREAK was not pressed: return a 0 */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize Maurice (a.k.a) and any attached devices
|
||||||
|
* Enable keyboard and mouse interrupts as appropriate.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Status code indicating if either the mouse or the keyboard is missing.
|
||||||
|
*/
|
||||||
|
short kbdmo_init() {
|
||||||
|
TRACE("kbdmo_init");
|
||||||
|
|
||||||
|
int_disable(INT_KBD_A2560K);
|
||||||
|
|
||||||
|
/* Turn off the LEDs */
|
||||||
|
kbdmo_set_led_matrix_fill(0);
|
||||||
|
|
||||||
|
/* Set up the ring buffers */
|
||||||
|
|
||||||
|
rb_word_init(&g_kbdmo_control.sc_buf); /* Scan-code ring buffer is empty */
|
||||||
|
rb_word_init(&g_kbdmo_control.char_buf); /* Character ring buffer is empty */
|
||||||
|
|
||||||
|
/* Set the default keyboard layout to US */
|
||||||
|
kbdmo_layout(g_us_kbdmo_layout);
|
||||||
|
|
||||||
|
g_kbdmo_control.status = 0;
|
||||||
|
g_kbdmo_control.modifiers = 0;
|
||||||
|
|
||||||
|
/* Make sure everything is read */
|
||||||
|
kbdmo_flush_out();
|
||||||
|
|
||||||
|
/* Turn off the LEDs */
|
||||||
|
kbdmo_leds = 0;
|
||||||
|
*GABE_MO_LEDS = kbdmo_leds;
|
||||||
|
|
||||||
|
/* Clear out any pending interrupt */
|
||||||
|
int_clear(INT_KBD_A2560K);
|
||||||
|
|
||||||
|
#ifndef KBD_POLLED
|
||||||
|
/* Register a handler for the keyboard */
|
||||||
|
int_register(INT_KBD_A2560K, kbdmo_handle_irq);
|
||||||
|
|
||||||
|
/* Enable the interrupt for the keyboard */
|
||||||
|
int_enable(INT_KBD_A2560K);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Toggle the lock bit based on the flag.
|
||||||
|
*/
|
||||||
|
void kbdmo_toggle_modifier(short flag) {
|
||||||
|
g_kbdmo_control.modifiers ^= flag;
|
||||||
|
|
||||||
|
if (flag == KBD_LOCK_CAPS) {
|
||||||
|
if (g_kbdmo_control.modifiers & flag) {
|
||||||
|
/* CAPS is on... set it to purple */
|
||||||
|
kbdmo_set_caps_led(5);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* CAPS is off... turn off the LED */
|
||||||
|
kbdmo_set_caps_led(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set or clear the modifier flag depending on if the scan code is a make or break code.
|
||||||
|
*/
|
||||||
|
void kbdmo_makebreak_modifier(short flag, short is_break) {
|
||||||
|
if (is_break) {
|
||||||
|
g_kbdmo_control.modifiers &= ~flag;
|
||||||
|
} else {
|
||||||
|
g_kbdmo_control.modifiers |= flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the scan code to the queue of scan codes
|
||||||
|
*/
|
||||||
|
void kbdmo_enqueue_scan(unsigned char scan_code) {
|
||||||
|
// Make sure the scan code isn't 0 or 128, which are invalid make/break codes
|
||||||
|
if ((scan_code != 0) && (scan_code != 0x80)) {
|
||||||
|
unsigned char is_break = scan_code & 0x80;
|
||||||
|
|
||||||
|
// If CTRL-C pressed, treat it as a break
|
||||||
|
if ((scan_code == g_kbdmo_break_sc) & ((g_kbdmo_control.modifiers & KBD_MOD_CTRL) != 0)) {
|
||||||
|
g_kbdmo_control.status |= KBD_STAT_BREAK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the scan code to see if it's a modifier key or a lock key
|
||||||
|
// update the modifier and lock variables accordingly...
|
||||||
|
switch (scan_code & 0x7f) {
|
||||||
|
case 0x01:
|
||||||
|
/* ESC key pressed... check to see if it's a press with the Foenix key */
|
||||||
|
if (((g_kbdmo_control.modifiers & KBD_MOD_OS) != 0) && (is_break == 0)) {
|
||||||
|
/* ESC pressed with Foenix key... flag a BREAK. */
|
||||||
|
g_kbdmo_control.status |= KBD_STAT_BREAK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x2A:
|
||||||
|
case 0x36:
|
||||||
|
kbdmo_makebreak_modifier(KBD_MOD_SHIFT, is_break);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x1D:
|
||||||
|
case 0x5E:
|
||||||
|
kbdmo_makebreak_modifier(KBD_MOD_CTRL, is_break);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x38:
|
||||||
|
case 0x5C:
|
||||||
|
kbdmo_makebreak_modifier(KBD_MOD_ALT, is_break);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5D:
|
||||||
|
kbdmo_makebreak_modifier(KBD_MOD_MENU, is_break);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x5B:
|
||||||
|
kbdmo_makebreak_modifier(KBD_MOD_OS, is_break);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x3A:
|
||||||
|
if (!is_break) kbdmo_toggle_modifier(KBD_LOCK_CAPS);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x45:
|
||||||
|
if (!is_break) kbdmo_toggle_modifier(KBD_LOCK_NUM);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x46:
|
||||||
|
if (!is_break) kbdmo_toggle_modifier(KBD_LOCK_SCROLL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_word_put(&g_kbdmo_control.sc_buf, g_kbdmo_control.modifiers << 8 | scan_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IRQ handler for the keyboard... read a scan code and queue it
|
||||||
|
*/
|
||||||
|
void kbdmo_handle_irq() {
|
||||||
|
unsigned long data;
|
||||||
|
/* We got an interrupt for MO.
|
||||||
|
* While there is data in the input queue...
|
||||||
|
*/
|
||||||
|
|
||||||
|
int_clear(INT_KBD_A2560K);
|
||||||
|
|
||||||
|
/* While there is data in the buffer ... */
|
||||||
|
do {
|
||||||
|
data = *KBD_MO_DATA;
|
||||||
|
|
||||||
|
/* Read and throw out the scan codes */
|
||||||
|
unsigned short scan_code = data & 0xffff;
|
||||||
|
if ((scan_code & 0x7fff) != 0) {
|
||||||
|
/* TODO: beep if the input was full or the ring buffer is full */
|
||||||
|
|
||||||
|
/* Process it and enqueue it */
|
||||||
|
kbdmo_enqueue_scan((unsigned char)(scan_code & 0x00ff));
|
||||||
|
}
|
||||||
|
} while ((data & 0x00ff0000) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to retrieve the next scancode from the keyboard.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* The next scancode to be processed, 0 if nothing.
|
||||||
|
*/
|
||||||
|
unsigned short kbdmo_get_scancode() {
|
||||||
|
unsigned long data;
|
||||||
|
unsigned short scan_code = rb_word_get(&g_kbdmo_control.sc_buf);
|
||||||
|
if (scan_code != 0) {
|
||||||
|
/* Got a result... return it */
|
||||||
|
return scan_code;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Catch special keys and convert them to their ANSI terminal codes
|
||||||
|
*
|
||||||
|
* Characters 0x80 - 0x98 are reserved for function keys, arrow keys, etc.
|
||||||
|
* This function maps them to the ANSI escape codes
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* modifiers = the current modifier bit flags (ALT, CTRL, META, etc)
|
||||||
|
* c = the character found from the scan code.
|
||||||
|
*/
|
||||||
|
static unsigned char kbd_to_ansi(unsigned char modifiers, unsigned char c) {
|
||||||
|
if ((c >= 0x80) && (c <= 0x98)) {
|
||||||
|
/* The key is a function key or a special control key */
|
||||||
|
const char * ansi_key = ansi_keys[c - 0x80];
|
||||||
|
const char * sequence;
|
||||||
|
short modifiers_after = 0;
|
||||||
|
|
||||||
|
// Figure out if the modifiers come before or after the sequence code
|
||||||
|
if (isdigit(ansi_key[0])) {
|
||||||
|
// Sequence is numeric, modifiers come after
|
||||||
|
modifiers_after = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// After ESC, all sequences have [
|
||||||
|
rb_word_put(&g_kbdmo_control.char_buf, '[');
|
||||||
|
|
||||||
|
if (modifiers_after) {
|
||||||
|
// Sequence is numberic, get the expanded sequence and put it in the queue
|
||||||
|
for (sequence = ansi_keys[c - 0x80]; *sequence != 0; sequence++) {
|
||||||
|
rb_word_put(&g_kbdmo_control.char_buf, *sequence);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see if we need to send a modifier sequence
|
||||||
|
if (modifiers & (KBD_MOD_SHIFT | KBD_MOD_CTRL | KBD_MOD_ALT | KBD_MOD_OS)) {
|
||||||
|
unsigned char code_bcd;
|
||||||
|
short modifier_code = 0;
|
||||||
|
short i;
|
||||||
|
|
||||||
|
if (modifiers_after) {
|
||||||
|
// Sequence is numeric, so put modifiers after the sequence and a semicolon
|
||||||
|
rb_word_put(&g_kbdmo_control.char_buf, ';');
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier_code = ((modifiers >> 3) & 0x1F) + 1;
|
||||||
|
code_bcd = i_to_bcd(modifier_code);
|
||||||
|
|
||||||
|
if (code_bcd & 0xF0) {
|
||||||
|
rb_word_put(&g_kbdmo_control.char_buf, ((code_bcd & 0xF0) >> 4) + '0');
|
||||||
|
}
|
||||||
|
rb_word_put(&g_kbdmo_control.char_buf, (code_bcd & 0x0F) + '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!modifiers_after) {
|
||||||
|
// Sequence is a letter code
|
||||||
|
rb_word_put(&g_kbdmo_control.char_buf, ansi_key[0]);
|
||||||
|
} else {
|
||||||
|
// Sequence is numeric, close it with a tilda
|
||||||
|
rb_word_put(&g_kbdmo_control.char_buf, '~');
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0x1B; /* Start the sequence with an escape */
|
||||||
|
|
||||||
|
} else if (c == 0x1B) {
|
||||||
|
/* ESC should be doubled, to distinguish from the start of an escape sequence */
|
||||||
|
rb_word_put(&g_kbdmo_control.char_buf, 0x1B);
|
||||||
|
return c;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Not a special key: return the character unmodified */
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to get a character from the keyboard...
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the next character to be read from the keyboard (0 if none available)
|
||||||
|
*/
|
||||||
|
unsigned char kbdmo_getc() {
|
||||||
|
if (!rb_word_empty(&g_kbdmo_control.char_buf)) {
|
||||||
|
// If there is a character waiting in the character buffer, return it...
|
||||||
|
return (char)rb_word_get(&g_kbdmo_control.char_buf);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Otherwise, we need to check the scan code queue...
|
||||||
|
unsigned short raw_code = kbdmo_get_scancode();
|
||||||
|
while (raw_code != 0) {
|
||||||
|
if ((raw_code & 0x80) == 0) {
|
||||||
|
// If it's a make code, let's try to look it up...
|
||||||
|
unsigned char modifiers = (raw_code >> 8) & 0xff; // Get the modifiers
|
||||||
|
unsigned char scan_code = raw_code & 0x7f; // Get the base code for the key
|
||||||
|
|
||||||
|
// Check the modifiers to see what we should lookup...
|
||||||
|
|
||||||
|
if ((modifiers & (KBD_MOD_ALT | KBD_MOD_SHIFT | KBD_MOD_CTRL | KBD_LOCK_CAPS)) == 0) {
|
||||||
|
// No modifiers... just return the base character
|
||||||
|
return kbd_to_ansi(modifiers, g_kbdmo_control.keys_unmodified[scan_code]);
|
||||||
|
|
||||||
|
} else if (modifiers & KBD_MOD_ALT) {
|
||||||
|
return kbd_to_ansi(modifiers, g_kbdmo_control.keys_alt[scan_code]);
|
||||||
|
|
||||||
|
} else if (modifiers & KBD_MOD_CTRL) {
|
||||||
|
// If CTRL is pressed...
|
||||||
|
if (modifiers & KBD_MOD_SHIFT) {
|
||||||
|
// If SHIFT is also pressed, return CTRL-SHIFT form
|
||||||
|
return kbd_to_ansi(modifiers, g_kbdmo_control.keys_control_shift[scan_code]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Otherwise, return just CTRL form
|
||||||
|
return kbd_to_ansi(modifiers, g_kbdmo_control.keys_control[scan_code]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (modifiers & KBD_LOCK_CAPS) {
|
||||||
|
// If CAPS is locked...
|
||||||
|
if (modifiers & KBD_MOD_SHIFT) {
|
||||||
|
// If SHIFT is also pressed, return CAPS-SHIFT form
|
||||||
|
return kbd_to_ansi(modifiers, g_kbdmo_control.keys_caps_shift[scan_code]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Otherwise, return just CAPS form
|
||||||
|
return kbd_to_ansi(modifiers, g_kbdmo_control.keys_caps[scan_code]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// SHIFT is pressed, return SHIFT form
|
||||||
|
return kbd_to_ansi(modifiers, g_kbdmo_control.keys_shift[scan_code]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reach this point, it wasn't a useful scan-code...
|
||||||
|
// So try to fetch another
|
||||||
|
raw_code = kbdmo_get_scancode();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reach this point, there are no useful scan codes
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use polling to fetch a key
|
||||||
|
*/
|
||||||
|
char kbdmo_getc_poll() {
|
||||||
|
kbdmo_handle_irq();
|
||||||
|
return kbdmo_getc();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use polling to fetch a scan code
|
||||||
|
*/
|
||||||
|
unsigned short kbdmo_get_scancode_poll() {
|
||||||
|
kbdmo_handle_irq();
|
||||||
|
return kbdmo_get_scancode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the color of the LED for the capslock
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* colors = color specification, three bits: 0x_____RGB
|
||||||
|
*/
|
||||||
|
void kbdmo_set_caps_led(short colors) {
|
||||||
|
kbdmo_leds = (kbdmo_leds & 0xF1FF) | ((colors & 0x07) << 9);
|
||||||
|
*GABE_MO_LEDS = kbdmo_leds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the color of the LED for the floppy drive
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* colors = color specification, three bits: 0x_____RGB
|
||||||
|
*/
|
||||||
|
void kbdmo_set_fdc_led(short colors) {
|
||||||
|
kbdmo_leds = (kbdmo_leds & 0xFFF8) | (colors & 0x07);
|
||||||
|
*GABE_MO_LEDS = kbdmo_leds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the color of the LED for the SD card slot
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* colors = color specification, three bits: 0x_____RGB
|
||||||
|
*/
|
||||||
|
void kbdmo_set_sdc_led(short colors) {
|
||||||
|
kbdmo_leds = (kbdmo_leds & 0xFFC7) | ((colors & 0x07) << 3);
|
||||||
|
*GABE_MO_LEDS = kbdmo_leds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the color of the LED for the IDE hard drive
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* colors = color specification, three bits: 0x_____RGB
|
||||||
|
*/
|
||||||
|
void kbdmo_set_hdc_led(short colors) {
|
||||||
|
kbdmo_leds = (kbdmo_leds & 0xFE3F) | ((colors & 0x07) << 6);
|
||||||
|
*GABE_MO_LEDS = kbdmo_leds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the keyboard translation tables
|
||||||
|
*
|
||||||
|
* The translation tables provided to the keyboard consist of eight
|
||||||
|
* consecutive tables of 128 characters each. Each table maps from
|
||||||
|
* the MAKE scan code of a key to its appropriate 8-bit character code.
|
||||||
|
*
|
||||||
|
* The tables included must include, in order:
|
||||||
|
* - UNMODIFIED: Used when no modifier keys are pressed or active
|
||||||
|
* - SHIFT: Used when the SHIFT modifier is pressed
|
||||||
|
* - CTRL: Used when the CTRL modifier is pressed
|
||||||
|
* - CTRL-SHIFT: Used when both CTRL and SHIFT are pressed
|
||||||
|
* - CAPSLOCK: Used when CAPSLOCK is down but SHIFT is not pressed
|
||||||
|
* - CAPSLOCK-SHIFT: Used when CAPSLOCK is down and SHIFT is pressed
|
||||||
|
* - ALT: Used when only ALT is presse
|
||||||
|
* - ALT-SHIFT: Used when ALT is pressed and either CAPSLOCK is down
|
||||||
|
* or SHIFT is pressed (but not both)
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* tables = pointer to the keyboard translation tables
|
||||||
|
*/
|
||||||
|
short kbdmo_layout(const char * tables) {
|
||||||
|
short i;
|
||||||
|
|
||||||
|
for (i = 0; i < 128; i++) {
|
||||||
|
g_kbdmo_control.keys_unmodified[i] = tables[i];
|
||||||
|
g_kbdmo_control.keys_shift[i] = tables[i + 128];
|
||||||
|
g_kbdmo_control.keys_control[i] = tables[i + 256];
|
||||||
|
if (g_kbdmo_control.keys_control[i] == 0x03) {
|
||||||
|
// We have set the scan code for CTRL-C?
|
||||||
|
g_kbdmo_break_sc = i;
|
||||||
|
}
|
||||||
|
// Check for CTRL-C
|
||||||
|
g_kbdmo_control.keys_control_shift[i] = tables[i + 384];
|
||||||
|
g_kbdmo_control.keys_caps[i] = tables[i + 512];
|
||||||
|
g_kbdmo_control.keys_caps_shift[i] = tables[i + 640];
|
||||||
|
g_kbdmo_control.keys_alt[i] = tables[i + 768];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
132
src/dev/kbd_mo.h
Normal file
132
src/dev/kbd_mo.h
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* Declarations for Mo, the built-in keyboard of the A2560K
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __KBD_MO_H
|
||||||
|
#define __KBD_MO_H
|
||||||
|
|
||||||
|
#include "sys_general.h"
|
||||||
|
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the PS2 controller and any attached devices
|
||||||
|
* Enable keyboard and mouse interrupts as appropriate.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Status code indicating if either the mouse or the keyboard is missing.
|
||||||
|
*/
|
||||||
|
extern short kbdmo_init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the color of the A2560K keyboard LED matrix
|
||||||
|
*
|
||||||
|
* @param row the number of the row to set (0 - 5)
|
||||||
|
* @param color the color for the LEDs: ARGB
|
||||||
|
*/
|
||||||
|
void kbdmo_set_led_matrix_row(unsigned char row, unsigned short color);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set all the LEDs to the same color
|
||||||
|
*
|
||||||
|
* @param color the color for the LEDs: ARGB
|
||||||
|
*/
|
||||||
|
void kbdmo_set_led_matrix_fill(unsigned short color);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check to see if a BREAK code has been pressed recently
|
||||||
|
* If so, return true and reset the internal flag.
|
||||||
|
*
|
||||||
|
* BREAK will be F-ESC on the A2560K
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* true if a BREAK has been pressed since the last check
|
||||||
|
*/
|
||||||
|
extern bool kbdmo_break();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to retrieve the next scancode from the keyboard.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* The next scancode to be processed, 0 if nothing.
|
||||||
|
*/
|
||||||
|
extern unsigned short kbdmo_get_scancode();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to get a character from the keyboard...
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the next character to be read from the keyboard (0 if none available)
|
||||||
|
*/
|
||||||
|
extern unsigned char kbdmo_getc();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use polling to fetch a key
|
||||||
|
*/
|
||||||
|
extern char kbdmo_getc_poll();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use polling to fetch a scan code
|
||||||
|
*/
|
||||||
|
extern unsigned short kbdmo_get_scancode_poll();
|
||||||
|
|
||||||
|
extern void kbdmo_handle_irq();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the color of the LED for the capslock
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* colors = color specification, three bits: 0x_____RGB
|
||||||
|
*/
|
||||||
|
extern void kbdmo_set_caps_led(short colors);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the color of the LED for the floppy drive
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* colors = color specification, three bits: 0x_____RGB
|
||||||
|
*/
|
||||||
|
extern void kbdmo_set_fdc_led(short colors);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the color of the LED for the SD card slot
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* colors = color specification, three bits: 0x_____RGB
|
||||||
|
*/
|
||||||
|
extern void kbdmo_set_sdc_led(short colors);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the color of the LED for the IDE hard drive
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* colors = color specification, three bits: 0x_____RGB
|
||||||
|
*/
|
||||||
|
extern void kbdmo_set_hdc_led(short colors);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the keyboard translation tables
|
||||||
|
*
|
||||||
|
* The translation tables provided to the keyboard consist of eight
|
||||||
|
* consecutive tables of 128 characters each. Each table maps from
|
||||||
|
* the MAKE scan code of a key to its appropriate 8-bit character code.
|
||||||
|
*
|
||||||
|
* The tables included must include, in order:
|
||||||
|
* - UNMODIFIED: Used when no modifier keys are pressed or active
|
||||||
|
* - SHIFT: Used when the SHIFT modifier is pressed
|
||||||
|
* - CTRL: Used when the CTRL modifier is pressed
|
||||||
|
* - CTRL-SHIFT: Used when both CTRL and SHIFT are pressed
|
||||||
|
* - CAPSLOCK: Used when CAPSLOCK is down but SHIFT is not pressed
|
||||||
|
* - CAPSLOCK-SHIFT: Used when CAPSLOCK is down and SHIFT is pressed
|
||||||
|
* - ALT: Used when only ALT is presse
|
||||||
|
* - ALT-SHIFT: Used when ALT is pressed and either CAPSLOCK is down
|
||||||
|
* or SHIFT is pressed (but not both)
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* tables = pointer to the keyboard translation tables
|
||||||
|
*/
|
||||||
|
extern short kbdmo_layout(const char * tables);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
175
src/dev/lpt.c
Normal file
175
src/dev/lpt.c
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* Parallel port printer driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "features.h"
|
||||||
|
#include "errors.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "lpt_reg.h"
|
||||||
|
#include "dev/lpt.h"
|
||||||
|
#include "dev/txt_screen.h"
|
||||||
|
#include "simpleio.h"
|
||||||
|
#include "sys_general.h"
|
||||||
|
#include "syscalls.h"
|
||||||
|
|
||||||
|
#if HAS_PARALLEL_PORT
|
||||||
|
|
||||||
|
#define MAX_LPT_JIFFIES 600
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait a little bit...
|
||||||
|
*/
|
||||||
|
void lpt_delay() {
|
||||||
|
long target_jiffies = sys_time_jiffies() + 1;
|
||||||
|
while (target_jiffies > sys_time_jiffies()) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the printer... assert the INIT pin to trigger a reset on the printer
|
||||||
|
*/
|
||||||
|
short lpt_initialize() {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Set the outputs to start the initialization process */
|
||||||
|
*LPT_CTRL_PORT = LPT_CTRL_SELECT;
|
||||||
|
lpt_delay();
|
||||||
|
|
||||||
|
/* Set the outputs to stop the initialization process */
|
||||||
|
*LPT_CTRL_PORT = LPT_CTRL_mINIT | LPT_CTRL_SELECT;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a connection to the printer... all we do is assert the SELECT pin
|
||||||
|
*/
|
||||||
|
short lpt_open(t_channel * chan, const uint8_t * path, short mode) {
|
||||||
|
lpt_initialize();
|
||||||
|
|
||||||
|
*LPT_CTRL_PORT = LPT_CTRL_mINIT | LPT_CTRL_SELECT;
|
||||||
|
|
||||||
|
// Write a dummy character to kick everything off
|
||||||
|
lpt_write_b(0, "\x00", 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the connection to the printer... all we do is deassert the SELECT pin
|
||||||
|
*/
|
||||||
|
short lpt_close(t_channel * chan) {
|
||||||
|
*LPT_CTRL_PORT = LPT_CTRL_mINIT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a character to the parallel port
|
||||||
|
*/
|
||||||
|
short lpt_write_b(p_channel chan, unsigned char b) {
|
||||||
|
/* This write routine is polled I/O. */
|
||||||
|
long target_jiffies = 0;
|
||||||
|
|
||||||
|
/* Wait until the printer is not busy */
|
||||||
|
target_jiffies = sys_time_jiffies() + MAX_LPT_JIFFIES;
|
||||||
|
while ((*LPT_STAT_PORT & LPT_STAT_nBUSY) != LPT_STAT_nBUSY) {
|
||||||
|
lpt_delay();
|
||||||
|
if (target_jiffies < sys_time_jiffies()) {
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send the byte */
|
||||||
|
*LPT_DATA_PORT = b;
|
||||||
|
|
||||||
|
/* Strobe the interface */
|
||||||
|
*LPT_CTRL_PORT = LPT_CTRL_mINIT | LPT_CTRL_SELECT;
|
||||||
|
lpt_delay();
|
||||||
|
*LPT_CTRL_PORT = LPT_CTRL_mINIT | LPT_CTRL_SELECT | LPT_CTRL_STROBE;
|
||||||
|
|
||||||
|
/* Wait until the printer is not busy */
|
||||||
|
target_jiffies = sys_time_jiffies() + MAX_LPT_JIFFIES;
|
||||||
|
while ((*LPT_STAT_PORT & LPT_STAT_nBUSY) != LPT_STAT_nBUSY) {
|
||||||
|
lpt_delay();
|
||||||
|
if (target_jiffies < sys_time_jiffies()) {
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char status = *LPT_STAT_PORT;
|
||||||
|
if ((status & (LPT_STAT_nERROR | LPT_STAT_PO)) != LPT_STAT_nERROR ) {
|
||||||
|
// Online, there's paper, not busy, and not in error
|
||||||
|
if (status & LPT_STAT_PO) {
|
||||||
|
return DEV_NOMEDIA;
|
||||||
|
} else {
|
||||||
|
return ERR_GENERAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write a buffer of bytes to the parallel port
|
||||||
|
*/
|
||||||
|
short lpt_write(p_channel chan, const uint8_t * buffer, short size) {
|
||||||
|
int i;
|
||||||
|
short result;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
result = lpt_write_b(chan, buffer[i]);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the status of the printer
|
||||||
|
*/
|
||||||
|
short lpt_status(p_channel chan) {
|
||||||
|
short result = 0;
|
||||||
|
|
||||||
|
// Get the status
|
||||||
|
unsigned char stat = *LPT_STAT_PORT;
|
||||||
|
|
||||||
|
// Conver the status bits to be consistent with channels
|
||||||
|
if ((stat & LPT_STAT_nERROR) == 0) result |= LPT_STATUS_ERROR;
|
||||||
|
if (stat & LPT_STAT_PO) result |= LPT_STATUS_PAPER;
|
||||||
|
if (stat & LPT_STAT_SELECT) result |= LPT_STATUS_ONLINE;
|
||||||
|
if ((stat & (LPT_STAT_nERROR | LPT_STAT_PO | LPT_STAT_nBUSY | LPT_STAT_SELECT)) == LPT_STAT_nERROR | LPT_STAT_nBUSY | LPT_STAT_SELECT) {
|
||||||
|
// Online, there's paper, not busy, and not in error
|
||||||
|
result |= LPT_STATUS_WRITABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install the LPT driver
|
||||||
|
*/
|
||||||
|
short lpt_install() {
|
||||||
|
t_dev_chan dev;
|
||||||
|
|
||||||
|
dev.name = "LPT";
|
||||||
|
dev.number = CDEV_LPT;
|
||||||
|
dev.init = 0;
|
||||||
|
dev.open = lpt_open;
|
||||||
|
dev.close = lpt_close;
|
||||||
|
dev.read = 0;
|
||||||
|
dev.readline = 0;
|
||||||
|
dev.read_b = 0;
|
||||||
|
dev.write = lpt_write;
|
||||||
|
dev.write_b = lpt_write_b;
|
||||||
|
dev.flush = 0;
|
||||||
|
dev.seek = 0;
|
||||||
|
dev.status = lpt_status;
|
||||||
|
dev.ioctrl = 0;
|
||||||
|
|
||||||
|
return cdev_register(&dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
20
src/dev/lpt.h
Normal file
20
src/dev/lpt.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Parallel printer port driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LPT_H
|
||||||
|
#define __LPT_H
|
||||||
|
|
||||||
|
#include "dev/channel.h"
|
||||||
|
|
||||||
|
#define LPT_STATUS_ERROR 0x02 /** The printer has encountered some error */
|
||||||
|
#define LPT_STATUS_WRITABLE 0x08 /** The printer can accept data (online, no error, has paper, not busy) */
|
||||||
|
#define LPT_STATUS_PAPER 0x10 /** The printer is out of paper */
|
||||||
|
#define LPT_STATUS_ONLINE 0x20 /** The printer is selected/online */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Install the LPT driver
|
||||||
|
*/
|
||||||
|
extern short lpt_install();
|
||||||
|
|
||||||
|
#endif
|
225
src/dev/midi.c
Normal file
225
src/dev/midi.c
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
/*
|
||||||
|
* Definitions for the MIDI ports
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "features.h"
|
||||||
|
#include "midi_reg.h"
|
||||||
|
#include "dev/channel.h"
|
||||||
|
#include "dev/midi.h"
|
||||||
|
#include "errors.h"
|
||||||
|
#include "simpleio.h"
|
||||||
|
#include "sys_general.h"
|
||||||
|
#include "timers.h"
|
||||||
|
|
||||||
|
#if HAS_MIDI_PORTS
|
||||||
|
|
||||||
|
/** Timeout for waiting on the MIDI interface */
|
||||||
|
const long midi_timeout = 60;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for data to be ready to read...
|
||||||
|
*
|
||||||
|
* @return 1 on success, 0 if there is a timeout
|
||||||
|
*/
|
||||||
|
short midi_can_read() {
|
||||||
|
long target = timers_jiffies() + midi_timeout;
|
||||||
|
do {
|
||||||
|
if ((*MIDI_STAT & MIDI_STAT_RX_EMPTY) == 0) {
|
||||||
|
// There is data waiting
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} while (target > timers_jiffies());
|
||||||
|
|
||||||
|
// We have waited too long
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for the MIDI transmiter to be empty...
|
||||||
|
*
|
||||||
|
* @return 1 on success, 0 if there is a timeout
|
||||||
|
*/
|
||||||
|
short midi_can_write() {
|
||||||
|
long target = timers_jiffies() + midi_timeout;
|
||||||
|
do {
|
||||||
|
if ((*MIDI_STAT & MIDI_STAT_TX_BUSY) != 0) {
|
||||||
|
// The transmit buffer is empty
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} while (target > timers_jiffies());
|
||||||
|
|
||||||
|
// We have waited too long
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a command to the MPU-401
|
||||||
|
*
|
||||||
|
* @param cmd the command byte
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
short midi_command(unsigned char cmd) {
|
||||||
|
/* Send the byte */
|
||||||
|
*MIDI_CMD = cmd;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initilialize the MIDI port
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
short midi_init() {
|
||||||
|
unsigned char dummy;
|
||||||
|
short result;
|
||||||
|
|
||||||
|
result = midi_command(0xFF); /* Reset the MIDI port */
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = midi_command(0x3F); /* Switch the MIDI port into UART mode */
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for the ACK */
|
||||||
|
do {
|
||||||
|
if (midi_can_read()) {
|
||||||
|
dummy = *MIDI_DATA;
|
||||||
|
} else {
|
||||||
|
// There was a timeout
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
} while (dummy != 0xFE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a byte to the MIDI port
|
||||||
|
*
|
||||||
|
* @param b the byte to send
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
short midi_write_b(p_channel chan, const unsigned char b) {
|
||||||
|
if (midi_can_write()) {
|
||||||
|
/* Send the byte */
|
||||||
|
*MIDI_DATA = b;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
// There was a timeout
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a buffer's worth of bytes to the MIDI port
|
||||||
|
*
|
||||||
|
* @param chan the channel record (ignored)
|
||||||
|
* @param buffer the array of bytes to send
|
||||||
|
* @param size the number of bytes to send
|
||||||
|
*/
|
||||||
|
short midi_write(p_channel chan, const unsigned char * buffer, short size) {
|
||||||
|
short i = 0;
|
||||||
|
short result = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
result = midi_write_b(chan, buffer[i]);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a byte from the MIDI port
|
||||||
|
*
|
||||||
|
* @param chan the channel record (ignored)
|
||||||
|
* @return the byte read, negative on error
|
||||||
|
*/
|
||||||
|
short midi_read_b(p_channel chan) {
|
||||||
|
if (midi_can_read()) {
|
||||||
|
return ((short)*MIDI_DATA & 0x00ff);
|
||||||
|
} else {
|
||||||
|
// There was a timeout
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a number of bytes from the MIDI port into the buffer
|
||||||
|
*
|
||||||
|
* @param chan the channel record (ignored)
|
||||||
|
* @param buffer the byte buffer into which to store the read data
|
||||||
|
* @size the number of bytes to read
|
||||||
|
*/
|
||||||
|
short midi_read(p_channel chan, unsigned char * buffer, short size) {
|
||||||
|
short i = 0;
|
||||||
|
short result = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
result = midi_read_b(chan);
|
||||||
|
if (result < 0) {
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
buffer[i] = (unsigned char)(result & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the status of the MIDI port
|
||||||
|
*
|
||||||
|
* @param chan the channel record (ignored)
|
||||||
|
* @return the channel status flags
|
||||||
|
*/
|
||||||
|
short midi_status(p_channel chan) {
|
||||||
|
short status = 0;
|
||||||
|
unsigned char midi_stat_value = *MIDI_STAT;
|
||||||
|
|
||||||
|
if ((midi_stat_value & MIDI_STAT_TX_BUSY) != 0) {
|
||||||
|
status |= CDEV_STAT_WRITABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((midi_stat_value & MIDI_STAT_RX_EMPTY) == 0) {
|
||||||
|
status |= CDEV_STAT_READABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
short midi_open(p_channel chan, const char * path, short mode) {
|
||||||
|
return midi_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install the driver for the MIDI port
|
||||||
|
*/
|
||||||
|
short midi_install() {
|
||||||
|
short result;
|
||||||
|
t_dev_chan dev;
|
||||||
|
|
||||||
|
dev.name = "MIDI";
|
||||||
|
dev.number = CDEV_MIDI;
|
||||||
|
dev.init = midi_init;
|
||||||
|
dev.open = midi_open;
|
||||||
|
dev.close = 0;
|
||||||
|
dev.read = midi_read;
|
||||||
|
dev.readline = 0;
|
||||||
|
dev.read_b = midi_read_b;
|
||||||
|
dev.write = midi_write;
|
||||||
|
dev.write_b = midi_write_b;
|
||||||
|
dev.flush = 0;
|
||||||
|
dev.seek = 0;
|
||||||
|
dev.status = midi_status;
|
||||||
|
dev.ioctrl = 0;
|
||||||
|
|
||||||
|
return cdev_register(&dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
13
src/dev/midi.h
Normal file
13
src/dev/midi.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
/*
|
||||||
|
* Declarations for the MIDI ports
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __MIDI_H
|
||||||
|
#define __MIDI_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install the driver for the MIDI port
|
||||||
|
*/
|
||||||
|
extern short midi_install();
|
||||||
|
|
||||||
|
#endif
|
722
src/dev/old/text_screen_iii.c
Normal file
722
src/dev/old/text_screen_iii.c
Normal file
|
@ -0,0 +1,722 @@
|
||||||
|
/*
|
||||||
|
* Driver for VICKY III text screens, both channel A and channel B
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
#include "vicky_general.h"
|
||||||
|
#include "dev/txt_screen.h"
|
||||||
|
#include "simpleio.h"
|
||||||
|
#include "sys_general.h"
|
||||||
|
#include "rsrc/font/MSX_CP437_8x8.h"
|
||||||
|
#include "rsrc/font/BM437_IBM_Model3_Alt4.h"
|
||||||
|
|
||||||
|
#define MAX_TEXT_CHANNELS 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure to hold pointers to the text channel's registers and memory
|
||||||
|
*/
|
||||||
|
typedef struct s_text_channel {
|
||||||
|
unsigned char current_color;
|
||||||
|
unsigned char * font_ptr;
|
||||||
|
|
||||||
|
volatile unsigned long * master_control;
|
||||||
|
volatile char * text_cells;
|
||||||
|
volatile char * color_cells;
|
||||||
|
volatile unsigned long * cursor_settings;
|
||||||
|
volatile unsigned long * cursor_position;
|
||||||
|
volatile unsigned long * border_control;
|
||||||
|
volatile unsigned long * font_size_ctrl;
|
||||||
|
volatile unsigned long * font_count_ctrl;
|
||||||
|
|
||||||
|
short columns_max;
|
||||||
|
short rows_max;
|
||||||
|
short columns_visible;
|
||||||
|
short rows_visible;
|
||||||
|
short font_size; /* 0 = 8x8, 1 = 8x16 */
|
||||||
|
|
||||||
|
short x;
|
||||||
|
short y;
|
||||||
|
volatile char * text_cursor_ptr;
|
||||||
|
volatile unsigned char * color_cursor_ptr;
|
||||||
|
} t_text_channel, *p_text_channel;
|
||||||
|
|
||||||
|
static t_text_channel text_channel[MAX_TEXT_CHANNELS];
|
||||||
|
|
||||||
|
// 0xHHLL, 0xHHLL
|
||||||
|
// 0xGGBB, 0xAARR
|
||||||
|
const unsigned short fg_color_lut [32] = {
|
||||||
|
0x0000, 0xFF00, // Black (transparent)
|
||||||
|
0x0000, 0xFF80, // Mid-Tone Red
|
||||||
|
0x8000, 0xFF00, // Mid-Tone Green
|
||||||
|
0x8000, 0xFF80, // Mid-Tone Yellow
|
||||||
|
0x0080, 0xFF00, // Mid-Tone Blue
|
||||||
|
0x5500, 0xFFAA, // Mid-Tone Orange
|
||||||
|
0x8080, 0xFF00, // Mid-Tone Cian
|
||||||
|
0x8080, 0xFF80, // 50% Grey
|
||||||
|
0x5555, 0xFF55, // Dark Grey
|
||||||
|
0x5555, 0xFFFF, // Bright Red
|
||||||
|
0xFF55, 0xFF55, // Bright Green
|
||||||
|
0xFF55, 0xFFFF, // Bright Yellow
|
||||||
|
0x55FF, 0xFF55, // Bright Blue
|
||||||
|
0x7FFF, 0xFFFF, // Bright Orange
|
||||||
|
0xFFFF, 0xFF55, // Bright Cyan
|
||||||
|
0xFFFF, 0xFFFF // White
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsigned short bg_color_lut [32] = {
|
||||||
|
0x0000, 0xFF00, // Black (transparent)
|
||||||
|
0x0000, 0xFF80, // Mid-Tone Red
|
||||||
|
0x8000, 0xFF00, // Mid-Tone Green
|
||||||
|
0x8000, 0xFF80, // Mid-Tone Yellow
|
||||||
|
0x0080, 0xFF00, // Mid-Tone Blue
|
||||||
|
0x8000, 0xFF80, // Mid-Tone Orange
|
||||||
|
0x8080, 0xFF00, // Mid-Tone Cian
|
||||||
|
0x8080, 0xFF80, // 50% Grey
|
||||||
|
0x5555, 0xFF55, // Dark Grey
|
||||||
|
0x5555, 0xFFFF, // Bright Red
|
||||||
|
0xFF55, 0xFF55, // Bright Green
|
||||||
|
0xFF55, 0xFFFF, // Bright Yellow
|
||||||
|
0x55FF, 0xFF55, // Bright Blue
|
||||||
|
0x7FFF, 0xFFFF, // Bright Orange
|
||||||
|
0xFFFF, 0xFF55, // Bright Cyan
|
||||||
|
0xFFFF, 0xFFFF // White
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the text screen driver
|
||||||
|
*/
|
||||||
|
int text_init() {
|
||||||
|
short need_hires = 1;
|
||||||
|
int i, x;
|
||||||
|
p_text_channel chan_a = &text_channel[0];
|
||||||
|
unsigned long border_color = 0;
|
||||||
|
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K
|
||||||
|
border_color = 0x00004000; /* Dark blue border for the K */
|
||||||
|
#elif MODEL == MODEL_FOENIX_GENX
|
||||||
|
border_color = 0x00200020;
|
||||||
|
#elif MODEL == MODEL_FOENIX_A2560X
|
||||||
|
border_color = 0x00002020;
|
||||||
|
#elif MODEL == MODEL_FOENIX_A2560U || MODEL == MODEL_FOENIX_A2560U_PLUS
|
||||||
|
border_color = 0x00008080; /* Dark blue border for the K */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K || MODEL == MODEL_FOENIX_GENX || MODEL == MODEL_FOENIX_A2560X
|
||||||
|
p_text_channel chan_b = &text_channel[1];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_TEXT_CHANNELS; i++) {
|
||||||
|
#pragma dontwarn 113 // only 0 should be assigned to pointer
|
||||||
|
text_channel[i].master_control = 0xffffffff;
|
||||||
|
text_channel[i].text_cells = 0xffffffff;
|
||||||
|
text_channel[i].color_cells = 0xffffffff;
|
||||||
|
text_channel[i].cursor_settings = 0xffffffff;
|
||||||
|
text_channel[i].cursor_position = 0xffffffff;
|
||||||
|
text_channel[i].border_control = 0xffffffff;
|
||||||
|
text_channel[i].text_cursor_ptr = 0xffffffff;
|
||||||
|
text_channel[i].color_cursor_ptr = 0xffffffff;
|
||||||
|
#pragma popwarn
|
||||||
|
text_channel[i].current_color = 0;
|
||||||
|
text_channel[i].columns_max = 0;
|
||||||
|
text_channel[i].rows_max = 0;
|
||||||
|
text_channel[i].columns_visible = 0;
|
||||||
|
text_channel[i].rows_visible = 0;
|
||||||
|
text_channel[i].x = 0;
|
||||||
|
text_channel[i].y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K || MODEL == MODEL_FOENIX_GENX || MODEL == MODEL_FOENIX_A2560X
|
||||||
|
// Init CLUT for the Color Memory
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
unsigned long fg_color = fg_color_lut[2*i + 1] << 16 | fg_color_lut[2*i];
|
||||||
|
unsigned long bg_color = bg_color_lut[2*i + 1] << 16 | bg_color_lut[2*i];
|
||||||
|
FG_CLUT_A[i] = fg_color;
|
||||||
|
BG_CLUT_A[i] = bg_color;
|
||||||
|
FG_CLUT_B[i] = fg_color;
|
||||||
|
BG_CLUT_B[i] = bg_color;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Init CLUT for the Color Memory
|
||||||
|
for (i = 0; i<32; i++) {
|
||||||
|
FG_CLUT_A[i] = fg_color_lut[i];
|
||||||
|
BG_CLUT_A[i] = bg_color_lut[i];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Initialize everything... only do a screen if it's present */
|
||||||
|
|
||||||
|
// need_hires = ((*VKY3_DIP_REG & VKY3_DIP_HIRES) == 0) ? 1 : 0;
|
||||||
|
|
||||||
|
chan_a->master_control = MasterControlReg_A;
|
||||||
|
chan_a->text_cells = ScreenText_A;
|
||||||
|
chan_a->color_cells = ColorText_A;
|
||||||
|
chan_a->cursor_settings = CursorControlReg_L_A;
|
||||||
|
chan_a->cursor_position = CursorControlReg_H_A;
|
||||||
|
chan_a->border_control = BorderControlReg_L_A;
|
||||||
|
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K || MODEL == MODEL_FOENIX_GENX || MODEL == MODEL_FOENIX_A2560X
|
||||||
|
/* A2560K has support for 8x16 characters and therefore font sizes */
|
||||||
|
chan_a->font_size_ctrl = FONT_Size_Ctrl_A;
|
||||||
|
chan_a->font_count_ctrl = FONT_Count_Ctrl_A;
|
||||||
|
need_hires = 0;
|
||||||
|
|
||||||
|
if (need_hires) {
|
||||||
|
*chan_a->master_control = VKY3_MCRA_1024x768 | VKY3_MCR_TEXT_EN; /* Set to text only mode: 800x600 */
|
||||||
|
} else {
|
||||||
|
*chan_a->master_control = VKY3_MCR_800x600 | VKY3_MCR_TEXT_EN; /* Set to text only mode: 800x600 */
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* All other models do not have this feature */
|
||||||
|
chan_a->font_size_ctrl = 0;
|
||||||
|
chan_a->font_count_ctrl = 0;
|
||||||
|
|
||||||
|
if (need_hires) {
|
||||||
|
*chan_a->master_control = VKY3_MCR_800x600 | VKY3_MCR_TEXT_EN; /* Set to text only mode: 800x600 */
|
||||||
|
} else {
|
||||||
|
*chan_a->master_control = VKY3_MCR_640x480 | VKY3_MCR_TEXT_EN; /* Set to text only mode: 640x480 */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (chan_a->font_size_ctrl) {
|
||||||
|
*chan_a->font_size_ctrl = 0x08080808; /* Font and container are 8x8 */
|
||||||
|
*chan_a->font_count_ctrl = 0x00004B64; /* 75 rows and 100 columns */
|
||||||
|
chan_a->font_size = 0; /* Set 8x16 */
|
||||||
|
|
||||||
|
} else {
|
||||||
|
chan_a->font_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
text_set_border(0, 1, 0x10, 0x10, border_color);
|
||||||
|
text_setsizes(0);
|
||||||
|
text_set_color(0, 0xf, 4);
|
||||||
|
text_set_cursor(0, 0xF3, 0x7F, 1, 1);
|
||||||
|
text_set_xy(0, 0, 0);
|
||||||
|
text_clear(0, 2);
|
||||||
|
|
||||||
|
/* Set the font for channel A */
|
||||||
|
if (chan_a->font_size == 1) {
|
||||||
|
/* Load the 8x16 font */
|
||||||
|
for (i = 0; i < 0x1000; i++) {
|
||||||
|
unsigned char b = BM437_IBM_Model3_Alt4[i];
|
||||||
|
VICKY_TXT_FONT_A[i] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cursor for this font */
|
||||||
|
text_set_cursor(0, 0xF3, 0xB0, 1, 1);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Load the 8x8 font */
|
||||||
|
for (i = 0; i < 0x800; i++) {
|
||||||
|
unsigned char b = MSX_CP437_8x8_bin[i];
|
||||||
|
VICKY_TXT_FONT_A[i] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cursor for this font */
|
||||||
|
text_set_border(0, 1, 0x20, 0x10, border_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K || MODEL == MODEL_FOENIX_GENX || MODEL == MODEL_FOENIX_A2560X
|
||||||
|
|
||||||
|
chan_b->master_control = MasterControlReg_B;
|
||||||
|
chan_b->text_cells = ScreenText_B;
|
||||||
|
chan_b->color_cells = ColorText_B;
|
||||||
|
chan_b->cursor_settings = CursorControlReg_L_B;
|
||||||
|
chan_b->cursor_position = CursorControlReg_H_B;
|
||||||
|
chan_b->border_control = BorderControlReg_L_B;
|
||||||
|
chan_b->font_size_ctrl = 0;
|
||||||
|
chan_b->font_count_ctrl = 0;
|
||||||
|
|
||||||
|
if (need_hires) {
|
||||||
|
*chan_b->master_control = VKY3_MCR_800x600 | VKY3_MCR_TEXT_EN; /* Set to text only mode: 800x600 */
|
||||||
|
} else {
|
||||||
|
*chan_b->master_control = VKY3_MCR_640x480 | VKY3_MCR_TEXT_EN; /* Set to text only mode: 640x480 */
|
||||||
|
}
|
||||||
|
|
||||||
|
text_set_border(1, 1, 0x20, 0x10, border_color);
|
||||||
|
text_setsizes(1);
|
||||||
|
text_set_color(1, 0x0f, 0x04);
|
||||||
|
text_clear(1, 2);
|
||||||
|
text_set_cursor(1, 0xF3, 0x7F, 1, 1);
|
||||||
|
text_set_xy(1, 0, 0);
|
||||||
|
|
||||||
|
/* Set the font for channel B */
|
||||||
|
|
||||||
|
for (i = 0; i < 0x800; i++) {
|
||||||
|
unsigned char b = MSX_CP437_8x8_bin[i];
|
||||||
|
VICKY_TXT_FONT_B[i] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the border
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* visible = 0 to hide, any other number to show
|
||||||
|
* width = the horizontal thickness of the border in pixels
|
||||||
|
* height = the vertical thickness of the border in pixels
|
||||||
|
* color = the RGB color (xxRRGGBB)
|
||||||
|
*/
|
||||||
|
void text_set_border(short screen, short visible, short width, short height, unsigned long color) {
|
||||||
|
if (screen < MAX_TEXT_CHANNELS) {
|
||||||
|
p_text_channel chan = &text_channel[screen];
|
||||||
|
|
||||||
|
if (visible) {
|
||||||
|
/* Set the width and color */
|
||||||
|
chan->border_control[0] = ((height & 0xff) << 16) | ((width & 0xff) << 8) | 1;
|
||||||
|
chan->border_control[1] = (color & 0x00ff0000) | ((color & 0xff) << 8) | ((color & 0xff00) >> 8);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Hide the border and make it 0 width */
|
||||||
|
chan->border_control[0] = 0;
|
||||||
|
chan->border_control[1] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the cursor properties
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* color = the color index for the cursor
|
||||||
|
* character = the character to display for the cursor
|
||||||
|
* rate = the rate of blinking (0 = 1 per sec, 1 = 2 per sec, 2 = 4 per sec, 3 = 5 per sec)
|
||||||
|
* enable = 1 to display the cursor, 0 to disable
|
||||||
|
*/
|
||||||
|
void text_set_cursor(short screen, short color, char character, short rate, short enable) {
|
||||||
|
if (screen < MAX_TEXT_CHANNELS) {
|
||||||
|
p_text_channel chan = &text_channel[screen];
|
||||||
|
*(chan->cursor_settings) = ((color & 0xff) << 24) | (character << 16) | ((rate & 0x02) << 1) | (enable & (0x01));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the position of the cursor on the screen. Adjusts internal pointers used for printing the characters
|
||||||
|
*
|
||||||
|
* If the x and y coordinates are out of bounds of the display, the routine will attempt to handle wrapping and
|
||||||
|
* scrolling accordingly.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* x = the column of the cursor (0 is left most)
|
||||||
|
* y = the row of the cursor (0 is right most)
|
||||||
|
*/
|
||||||
|
void text_set_xy(short screen, unsigned short x, unsigned short y) {
|
||||||
|
if (screen < MAX_TEXT_CHANNELS) {
|
||||||
|
/* TODO: add in wrapping and scrolling */
|
||||||
|
p_text_channel chan = &text_channel[screen];
|
||||||
|
|
||||||
|
if (x >= chan->columns_visible) {
|
||||||
|
x = 0;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y >= chan->rows_visible) {
|
||||||
|
y = chan->rows_visible - 1;
|
||||||
|
text_scroll(screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
chan->x = x;
|
||||||
|
chan->y = y;
|
||||||
|
|
||||||
|
*(chan->cursor_position) = ((unsigned long)y << 16) | (unsigned long)x;
|
||||||
|
short offset = y * chan->columns_max + x;
|
||||||
|
chan->text_cursor_ptr = &chan->text_cells[offset];
|
||||||
|
chan->color_cursor_ptr = &chan->color_cells[offset];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the position of the cursor on the screen.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* x = pointer to the location to store the column (0 is left most)
|
||||||
|
* y = pointer to the location to store the row (0 is right most)
|
||||||
|
*/
|
||||||
|
void text_get_xy(short screen, unsigned short * x, unsigned short * y) {
|
||||||
|
p_text_channel chan = &text_channel[screen];
|
||||||
|
|
||||||
|
*x = chan->x;
|
||||||
|
*y = chan->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the size information for the text screen based on the current settings in VICKY
|
||||||
|
* These settings are needed to correctly position text on the screen.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
*/
|
||||||
|
void text_setsizes(short screen) {
|
||||||
|
if (screen < MAX_TEXT_CHANNELS) {
|
||||||
|
uint32_t border = 0;
|
||||||
|
short pixel_double = 0;
|
||||||
|
short resolution = 0;
|
||||||
|
p_text_channel chan = &text_channel[screen];
|
||||||
|
|
||||||
|
border = *chan->border_control;
|
||||||
|
pixel_double = *chan->master_control & VKY3_MCR_DOUBLE_EN;
|
||||||
|
resolution = (*chan->master_control & VKY3_MCR_RESOLUTION_MASK) >> 8;
|
||||||
|
|
||||||
|
/* Set number of maximum rows and columns based on the base resolution */
|
||||||
|
switch (resolution) {
|
||||||
|
case 0: /* 640x480 */
|
||||||
|
chan->columns_max = 80;
|
||||||
|
chan->rows_max = 60;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: /* 800x600 */
|
||||||
|
chan->columns_max = 100;
|
||||||
|
chan->rows_max = 75;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: /* 1024x768 */
|
||||||
|
chan->columns_max = 128;
|
||||||
|
chan->rows_max = 96;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: /* 640x400 */
|
||||||
|
chan->columns_max = 80;
|
||||||
|
chan->rows_max = 50;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we are pixel doubling, characters are twice as big */
|
||||||
|
if (pixel_double) {
|
||||||
|
chan->columns_max /= 2;
|
||||||
|
chan->rows_max /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan->font_size == 1) {
|
||||||
|
chan->rows_max /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate visible rows and columns assuming no border */
|
||||||
|
chan->rows_visible = chan->rows_max;
|
||||||
|
chan->columns_visible = chan->columns_max;
|
||||||
|
|
||||||
|
/* If the border is enabled, subtract it from the visible rows and columns */
|
||||||
|
if (border & VKY3_BRDR_EN) {
|
||||||
|
short border_width = (border & VKY3_X_SIZE_MASK) >> 8;
|
||||||
|
short border_height = (border & VKY3_Y_SIZE_MASK) >> 16;
|
||||||
|
|
||||||
|
short columns_reduction = border_width / 4;
|
||||||
|
short rows_reduction = border_height / 4;
|
||||||
|
|
||||||
|
if (pixel_double) {
|
||||||
|
columns_reduction /= 2;
|
||||||
|
rows_reduction /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chan->font_size == 1) {
|
||||||
|
rows_reduction /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
chan->columns_visible -= columns_reduction;
|
||||||
|
chan->rows_visible -= rows_reduction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the foreground and background color for printing
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* foreground = the foreground color number to use (0 - 15)
|
||||||
|
* background = the background color number to use (0 - 15)
|
||||||
|
*/
|
||||||
|
void text_set_color(short screen, short foreground, short background) {
|
||||||
|
if (screen < MAX_TEXT_CHANNELS) {
|
||||||
|
p_text_channel chan = &text_channel[screen];
|
||||||
|
chan->current_color = ((foreground & 0x0f) << 4) | (background & 0x0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the foreground and background color for printing
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* foreground = pointer to the foreground color number
|
||||||
|
* background = pointer to the background color number
|
||||||
|
*/
|
||||||
|
void text_get_color(short screen, short * foreground, short * background) {
|
||||||
|
if (screen < MAX_TEXT_CHANNELS) {
|
||||||
|
p_text_channel chan = &text_channel[screen];
|
||||||
|
*foreground = (chan->current_color >> 4) & 0x0f;
|
||||||
|
*background = chan->current_color & 0x0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear the screen of data
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* mode = 0: erase from the cursor to the end of the screen,
|
||||||
|
1: erase from start of the screen to the cursor,
|
||||||
|
2: erase entire screen
|
||||||
|
*/
|
||||||
|
void text_clear(short screen, short mode) {
|
||||||
|
if (screen < MAX_TEXT_CHANNELS) {
|
||||||
|
int i;
|
||||||
|
int sos_index = 0;
|
||||||
|
p_text_channel chan = &text_channel[screen];
|
||||||
|
int eos_index = chan->columns_max * chan->rows_max;
|
||||||
|
int cursor_index = chan->y * chan->columns_max + chan->x;
|
||||||
|
|
||||||
|
// switch (mode) {
|
||||||
|
// case 0:
|
||||||
|
// /* Clear from cursor to the end of the screen */
|
||||||
|
// for (i = cursor_index; i < eos_index; i++) {
|
||||||
|
// chan->text_cells[i] = ' ';
|
||||||
|
// chan->color_cells[i] = chan->current_color;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case 1:
|
||||||
|
// /* Clear from (0, 0) to cursor */
|
||||||
|
// for (i = sos_index; i <= cursor_index; i++) {
|
||||||
|
// chan->text_cells[i] = ' ';
|
||||||
|
// chan->color_cells[i] = chan->current_color;
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// case 2:
|
||||||
|
/* Clear entire screen */
|
||||||
|
for (i = 0; i < 0x2000; i++) {
|
||||||
|
chan->text_cells[i] = ' ';
|
||||||
|
chan->color_cells[i] = chan->current_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// default:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear part or all of the current line
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* mode = 0: erase from the cursor to the end of the line
|
||||||
|
* 1: erase from the start of the line to the cursor
|
||||||
|
* 2: erase entire line
|
||||||
|
*/
|
||||||
|
void text_clear_line(short screen, short mode) {
|
||||||
|
if (screen < MAX_TEXT_CHANNELS) {
|
||||||
|
int i;
|
||||||
|
p_text_channel chan = &text_channel[screen];
|
||||||
|
int sol_index = chan->y * chan->columns_max;
|
||||||
|
int eol_index = (chan->y + 1) * chan->columns_max;
|
||||||
|
int cursor_index = chan->y * chan->columns_max + chan->x;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 0:
|
||||||
|
/* Clear from cursor to the end of the line */
|
||||||
|
for (i = cursor_index; i < eol_index; i++) {
|
||||||
|
chan->text_cells[i] = ' ';
|
||||||
|
chan->color_cells[i] = chan->current_color;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
/* Clear from (0, y) to cursor */
|
||||||
|
for (i = sol_index; i <= cursor_index; i++) {
|
||||||
|
chan->text_cells[i] = ' ';
|
||||||
|
chan->color_cells[i] = chan->current_color;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
/* Clear entire screen */
|
||||||
|
for (i = sol_index; i < eol_index; i++) {
|
||||||
|
chan->text_cells[i] = ' ';
|
||||||
|
chan->color_cells[i] = chan->current_color;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert a number of characters at the cursor position
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* count = the number of characters to insert
|
||||||
|
*/
|
||||||
|
void text_insert(short screen, short count) {
|
||||||
|
int i;
|
||||||
|
p_text_channel chan = &text_channel[screen];
|
||||||
|
int eol_index = (chan->y + 1) * chan->columns_max - 1;
|
||||||
|
int cursor_index = chan->y * chan->columns_max + chan->x;
|
||||||
|
|
||||||
|
for (i = cursor_index; i < eol_index; i++) {
|
||||||
|
chan->text_cells[i+1] = chan->text_cells[i];
|
||||||
|
chan->color_cells[i+1] = chan->color_cells[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
chan->text_cells[cursor_index] = ' ';
|
||||||
|
chan->color_cells[cursor_index] = chan->current_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete a number of characters at the cursor position
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* count = the number of characters to delete
|
||||||
|
*/
|
||||||
|
void text_delete(short screen, short count) {
|
||||||
|
int i;
|
||||||
|
p_text_channel chan = &text_channel[screen];
|
||||||
|
int eol_index = (chan->y + 1) * chan->columns_max - 1;
|
||||||
|
int cursor_index = chan->y * chan->columns_max + chan->x;
|
||||||
|
|
||||||
|
for (i = cursor_index; i < eol_index; i++) {
|
||||||
|
chan->text_cells[i] = chan->text_cells[i+1];
|
||||||
|
chan->color_cells[i] = chan->color_cells[i+1];
|
||||||
|
}
|
||||||
|
|
||||||
|
chan->text_cells[eol_index] = ' ';
|
||||||
|
chan->color_cells[eol_index] = chan->current_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scroll the text screen up one row
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
*/
|
||||||
|
void text_scroll(short screen) {
|
||||||
|
if (screen < MAX_TEXT_CHANNELS) {
|
||||||
|
short row, column;
|
||||||
|
p_text_channel chan = &text_channel[screen];
|
||||||
|
|
||||||
|
#if MODEL == MODEL_FOENIX_A2560K || MODEL == MODEL_FOENIX_GENX || MODEL == MODEL_FOENIX_A2560X
|
||||||
|
for (row = 0; row < chan->rows_visible - 1; row++) {
|
||||||
|
short offset1 = row * chan->columns_max;
|
||||||
|
short offset2 = (row + 1) * chan->columns_max;
|
||||||
|
volatile unsigned char * text_dest = &chan->text_cells[offset1];
|
||||||
|
volatile unsigned char * color_dest = &chan->color_cells[offset1];
|
||||||
|
volatile unsigned char * text_src = &chan->text_cells[offset2];
|
||||||
|
volatile unsigned char * color_src = &chan->color_cells[offset2];
|
||||||
|
|
||||||
|
for (column = 0; column < chan->columns_max; column++) {
|
||||||
|
*text_dest++ = *text_src++;
|
||||||
|
*color_dest++ = *color_src++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
short offset3 = (chan->rows_visible - 1) * chan->columns_max;
|
||||||
|
volatile unsigned char * text_dest = &chan->text_cells[offset3];
|
||||||
|
volatile unsigned char * color_dest = &chan->color_cells[offset3];
|
||||||
|
uint8_t color = chan->current_color;
|
||||||
|
for (column = 0; column < chan->columns_max; column++) {
|
||||||
|
*text_dest++ = ' ';
|
||||||
|
*color_dest++ = color;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for (row = 0; row < chan->rows_visible - 1; row++) {
|
||||||
|
short offset1 = row * chan->columns_max;
|
||||||
|
short offset2 = (row + 1) * chan->columns_max;
|
||||||
|
volatile short * text_dest = (short*)&chan->text_cells[offset1];
|
||||||
|
volatile short * color_dest = (short*)&chan->color_cells[offset1];
|
||||||
|
volatile short * text_src = (short*)&chan->text_cells[offset2];
|
||||||
|
volatile short * color_src = (short*)&chan->color_cells[offset2];
|
||||||
|
|
||||||
|
for (column = 0; column < chan->columns_max; column += 2) {
|
||||||
|
*text_dest++ = *text_src++;
|
||||||
|
*color_dest++ = *color_src++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
short offset3 = (chan->rows_visible - 1) * chan->columns_max;
|
||||||
|
volatile short * text_dest = (short*)&chan->text_cells[offset3];
|
||||||
|
volatile short * color_dest = (short*)&chan->color_cells[offset3];
|
||||||
|
uint8_t color = chan->current_color;
|
||||||
|
for (column = 0; column < chan->columns_max; column += 2) {
|
||||||
|
*text_dest++ = ' ';
|
||||||
|
*color_dest++ = color << 8 | color;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send a character to the screen without any escape code interpretation
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* c = the character to print
|
||||||
|
*/
|
||||||
|
void text_put_raw(short screen, char c) {
|
||||||
|
if (screen < MAX_TEXT_CHANNELS) {
|
||||||
|
short x, y;
|
||||||
|
p_text_channel chan = &text_channel[screen];
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case CHAR_NL:
|
||||||
|
text_set_xy(screen, 0, chan->y + 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHAR_CR:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHAR_BS:
|
||||||
|
if (chan->x > 0) {
|
||||||
|
text_set_xy(screen, chan->x - 1, chan->y);
|
||||||
|
*chan->text_cursor_ptr = ' ';
|
||||||
|
*chan->color_cursor_ptr = chan->current_color;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHAR_TAB:
|
||||||
|
text_get_xy(screen, &x, &y);
|
||||||
|
x = x + 8;
|
||||||
|
text_set_xy(screen, x, y);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
*chan->text_cursor_ptr++ = c;
|
||||||
|
*chan->color_cursor_ptr++ = chan->current_color;
|
||||||
|
text_set_xy(screen, chan->x + 1, chan->y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets the size of the test screen in rows and columns
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* columns = pointer to a short in which to store the number of columns
|
||||||
|
* rows = pointer to a short in which to store the number of rows
|
||||||
|
*/
|
||||||
|
void text_getsize(short screen, short * columns, short * rows) {
|
||||||
|
if (screen < MAX_TEXT_CHANNELS) {
|
||||||
|
short x, y;
|
||||||
|
p_text_channel chan = &text_channel[screen];
|
||||||
|
|
||||||
|
*columns = chan->columns_visible;
|
||||||
|
*rows = chan->rows_visible;
|
||||||
|
}
|
||||||
|
}
|
155
src/dev/old/text_screen_iii.h
Normal file
155
src/dev/old/text_screen_iii.h
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
#ifndef __TEXT_SCREEN_III_H
|
||||||
|
#define __TEXT_SCREEN_III_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver for VICKY III text screens, both channel A and channel B
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the text screen driver
|
||||||
|
*/
|
||||||
|
extern int text_init();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the cursor properties
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* color = the color index for the cursor
|
||||||
|
* character = the character to display for the cursor
|
||||||
|
* rate = the rate of blinking (0 = 1 per sec, 1 = 2 per sec, 2 = 4 per sec, 3 = 5 per sec)
|
||||||
|
* enable = 1 to display the cursor, 0 to disable
|
||||||
|
*/
|
||||||
|
extern void text_set_cursor(short screen, short color, char character, short rate, short enable);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the border
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* visible = 0 to hide, any other number to show
|
||||||
|
* width = the horizontal thickness of the border in pixels
|
||||||
|
* height = the vertical thickness of the border in pixels
|
||||||
|
* color = the RGB color (xxRRGGBB)
|
||||||
|
*/
|
||||||
|
extern void text_set_border(short screen, short visible, short width, short height, unsigned long color);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the position of the cursor on the screen. Adjusts internal pointers used for printing the characters
|
||||||
|
*
|
||||||
|
* If the x and y coordinates are out of bounds of the display, the routine will attempt to handle wrapping and
|
||||||
|
* scrolling accordingly.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* x = the column of the cursor (0 is left most)
|
||||||
|
* y = the row of the cursor (0 is right most)
|
||||||
|
*/
|
||||||
|
extern void text_set_xy(short screen, unsigned short x, unsigned short y);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the position of the cursor on the screen.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* x = pointer to the location to store the column (0 is left most)
|
||||||
|
* y = pointer to the location to store the row (0 is right most)
|
||||||
|
*/
|
||||||
|
extern void text_get_xy(short screen, unsigned short * x, unsigned short * y);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the size information for the text screen based on the current settings in VICKY
|
||||||
|
* These settings are needed to correctly position text on the screen.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
*/
|
||||||
|
extern void text_setsizes(short screen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send a character to the screen without any escape code interpretation
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* c = the character to print
|
||||||
|
*/
|
||||||
|
extern void text_put_raw(short screen, char c);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the foreground and background color for printing
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* foreground = the foreground color number to use (0 - 15)
|
||||||
|
* background = the background color number to use (0 - 15)
|
||||||
|
*/
|
||||||
|
extern void text_set_color(short screen, short foreground, short background);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the foreground and background color for printing
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* foreground = pointer to the foreground color number
|
||||||
|
* background = pointer to the background color number
|
||||||
|
*/
|
||||||
|
extern void text_get_color(short screen, short * foreground, short * background);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear the screen of data
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* mode = 0: erase from the cursor to the end of the screen,
|
||||||
|
1: erase from start of the screen to the cursor,
|
||||||
|
2: erase entire screen
|
||||||
|
*/
|
||||||
|
extern void text_clear(short screen, short mode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear part or all of the current line
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* mode = 0: erase from the start of the line to the cursor,
|
||||||
|
* 1: erase from cursor to end of the line,
|
||||||
|
* 2: erase entire line
|
||||||
|
*/
|
||||||
|
extern void text_clear_line(short screen, short mode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert a number of characters at the cursor position
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* count = the number of characters to insert
|
||||||
|
*/
|
||||||
|
extern void text_insert(short screen, short count);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete a number of characters at the cursor position
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* count = the number of characters to delete
|
||||||
|
*/
|
||||||
|
extern void text_delete(short screen, short count);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scroll the text screen up one row
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
*/
|
||||||
|
extern void text_scroll(short screen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets the size of the test screen in rows and columns
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* columns = pointer to a short in which to store the number of columns
|
||||||
|
* rows = pointer to a short in which to store the number of rows
|
||||||
|
*/
|
||||||
|
extern void text_getsize(short screen, short * columns, short * rows);
|
||||||
|
|
||||||
|
#endif
|
590
src/dev/pata.c
Normal file
590
src/dev/pata.c
Normal file
|
@ -0,0 +1,590 @@
|
||||||
|
/**
|
||||||
|
* Implementation of the PATA hard drive low level driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "log.h"
|
||||||
|
#include "errors.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "indicators.h"
|
||||||
|
#include "dev/block.h"
|
||||||
|
#include "dev/pata.h"
|
||||||
|
#include "dev/txt_screen.h"
|
||||||
|
#include "dev/rtc.h"
|
||||||
|
#include "pata_reg.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// Constants
|
||||||
|
//
|
||||||
|
|
||||||
|
#define PATA_TIMEOUT_JF 20 /* Timeout in jiffies: 1/60th second */
|
||||||
|
#define PATA_WAIT_JF 10 /* Delay in jiffies: 1/60th second */
|
||||||
|
|
||||||
|
//
|
||||||
|
// Variables
|
||||||
|
//
|
||||||
|
|
||||||
|
short g_pata_error = 0; // Most recent error code received from the PATA drive
|
||||||
|
short g_pata_status = PATA_STAT_NOINIT; // Status of the PATA interface
|
||||||
|
|
||||||
|
//
|
||||||
|
// Code
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Wait until the PATA drive is no longer busy, or we've run out of time
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success (PATA drive is no longer busy), DEV_TIMEOUT on timeout
|
||||||
|
//
|
||||||
|
short pata_wait_not_busy() {
|
||||||
|
long target_ticks;
|
||||||
|
long ticks = 0;
|
||||||
|
char status = 0;
|
||||||
|
|
||||||
|
TRACE("pata_wait_not_busy");
|
||||||
|
|
||||||
|
target_ticks = rtc_get_jiffies() + PATA_TIMEOUT_JF;
|
||||||
|
do {
|
||||||
|
status = *PATA_CMD_STAT;
|
||||||
|
ticks = rtc_get_jiffies();
|
||||||
|
} while ((status & PATA_STAT_BSY) && (target_ticks > ticks));
|
||||||
|
|
||||||
|
if (target_ticks <= ticks) {
|
||||||
|
log(LOG_ERROR, "pata_wait_not_busy: timeout");
|
||||||
|
log_num(LOG_ERROR, "target_ticks: ", (int)target_ticks);
|
||||||
|
log_num(LOG_ERROR, "ticks: ", (int)ticks);
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Wait until the PATA drive is ready, or we've run out of time
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success (PATA drive is ready), DEV_TIMEOUT on timeout
|
||||||
|
//
|
||||||
|
short pata_wait_ready() {
|
||||||
|
long target_ticks;
|
||||||
|
long ticks = 0;
|
||||||
|
char status = 0;
|
||||||
|
|
||||||
|
TRACE("pata_wait_ready");
|
||||||
|
|
||||||
|
target_ticks = rtc_get_jiffies() + PATA_TIMEOUT_JF;
|
||||||
|
do {
|
||||||
|
status = *PATA_CMD_STAT;
|
||||||
|
ticks = rtc_get_jiffies();
|
||||||
|
} while (((status & PATA_STAT_DRDY) == 0) && (target_ticks > ticks));
|
||||||
|
|
||||||
|
if (target_ticks <= ticks) {
|
||||||
|
log(LOG_ERROR, "pata_wait_ready: timeout");
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Wait until the PATA drive is ready and not busy, or we've run out of time
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success (PATA drive is ready and not busy), DEV_TIMEOUT on timeout
|
||||||
|
//
|
||||||
|
short pata_wait_ready_not_busy() {
|
||||||
|
long target_ticks = 0;
|
||||||
|
long ticks = 0;
|
||||||
|
char status = 0;
|
||||||
|
|
||||||
|
TRACE("pata_wait_ready_not_busy");
|
||||||
|
|
||||||
|
// do {
|
||||||
|
// status = *PATA_CMD_STAT;
|
||||||
|
// } while (((status & (PATA_STAT_DRDY | PATA_STAT_BSY)) != PATA_STAT_DRDY) && (count-- > 0));
|
||||||
|
|
||||||
|
target_ticks = rtc_get_jiffies() + PATA_TIMEOUT_JF;
|
||||||
|
do {
|
||||||
|
while (((*PATA_CMD_STAT & PATA_STAT_DRDY) != PATA_STAT_DRDY) && (target_ticks > ticks)) {
|
||||||
|
ticks = rtc_get_jiffies();
|
||||||
|
}
|
||||||
|
} while (((*PATA_CMD_STAT & PATA_STAT_BSY) == PATA_STAT_BSY) && (target_ticks > ticks));
|
||||||
|
|
||||||
|
if (target_ticks <= ticks) {
|
||||||
|
log(LOG_ERROR, "pata_wait_ready_not_busy: timeout");
|
||||||
|
log_num(LOG_ERROR, "target_ticks: ", (int)target_ticks);
|
||||||
|
log_num(LOG_ERROR, "ticks: ", (int)ticks);
|
||||||
|
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Wait until the PATA drive is ready to transfer data, or we've run out of time
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success (PATA drive is ready to transfer data), DEV_TIMEOUT on timeout
|
||||||
|
//
|
||||||
|
short pata_wait_data_request() {
|
||||||
|
long target_ticks = 0;
|
||||||
|
long ticks = 0;
|
||||||
|
char status = 0;
|
||||||
|
|
||||||
|
TRACE("pata_wait_data_request");
|
||||||
|
|
||||||
|
target_ticks = rtc_get_jiffies() + PATA_TIMEOUT_JF;
|
||||||
|
do {
|
||||||
|
status = *PATA_CMD_STAT;
|
||||||
|
ticks = rtc_get_jiffies();
|
||||||
|
} while (((status & PATA_STAT_DRQ) != PATA_STAT_DRQ) && (target_ticks > ticks));
|
||||||
|
|
||||||
|
if (target_ticks <= ticks) {
|
||||||
|
log(LOG_ERROR, "pata_wait_data_request: timeout");
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char g_buffer[512];
|
||||||
|
|
||||||
|
//
|
||||||
|
// Identify the PATA drive
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// drive_info = pointer to a s_drive_info
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
short pata_identity(p_drive_info drive_info) {
|
||||||
|
char * buffer = 0;
|
||||||
|
unsigned short *wptr;
|
||||||
|
char * cptr;
|
||||||
|
short i;
|
||||||
|
short count;
|
||||||
|
TRACE("pata_identity");
|
||||||
|
|
||||||
|
*PATA_HEAD = 0xe0; // Drive 0, lBA enabled, Head 0
|
||||||
|
*PATA_SECT_CNT = 1;
|
||||||
|
*PATA_SECT_SRT = 0;
|
||||||
|
*PATA_CLDR_LO = 0;
|
||||||
|
*PATA_CLDR_HI = 0;
|
||||||
|
|
||||||
|
// Issue identity command
|
||||||
|
*PATA_CMD_STAT = PATA_CMD_IDENTITY;
|
||||||
|
if (pata_wait_not_busy()) {
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Wait ~500ns
|
||||||
|
|
||||||
|
if (pata_wait_ready_not_busy()) {
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("copying data");
|
||||||
|
|
||||||
|
// Copy the data... let the compiler and the FPGA worry about endianess
|
||||||
|
wptr = (unsigned short *)g_buffer;
|
||||||
|
for (i = 0; i < 512; ) {
|
||||||
|
unsigned short data = *PATA_DATA_16;
|
||||||
|
g_buffer[i++] = data & 0xff;
|
||||||
|
g_buffer[i++] = (data >> 8) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("data copied");
|
||||||
|
|
||||||
|
drive_info->flags = (long) g_buffer[1] << 16 | g_buffer[0];
|
||||||
|
drive_info->lba_enabled = (long) g_buffer[99] << 16 | g_buffer[98];
|
||||||
|
drive_info->l.lbaw.lba_default_lo = g_buffer[121] << 8 | g_buffer[120];
|
||||||
|
drive_info->l.lbaw.lba_default_hi = g_buffer[123] << 8 | g_buffer[122];
|
||||||
|
|
||||||
|
// Copy the serial number (need to swap chars)
|
||||||
|
memcpy(&(drive_info->serial_number), g_buffer + 22, sizeof(drive_info->serial_number));
|
||||||
|
|
||||||
|
// Copy the firmware version (need to swap chars)
|
||||||
|
memcpy(&(drive_info->firmware_version), g_buffer + 46, sizeof(drive_info->firmware_version));
|
||||||
|
|
||||||
|
// Copy the model name (need to swap chars)
|
||||||
|
memcpy(&(drive_info->model_name), g_buffer + 54, sizeof(drive_info->model_name));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the PATA hard drive
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
short pata_init() {
|
||||||
|
short result;
|
||||||
|
|
||||||
|
TRACE("pata_init");
|
||||||
|
|
||||||
|
// Issue intialize command
|
||||||
|
*PATA_CMD_STAT = PATA_CMD_INIT;
|
||||||
|
if (pata_wait_not_busy()) {
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*PATA_HEAD = 0xA0; // Drive 0, lBA enabled, Head 0
|
||||||
|
*PATA_SECT_CNT = 1;
|
||||||
|
*PATA_SECT_SRT = 0;
|
||||||
|
*PATA_CLDR_LO = 0;
|
||||||
|
*PATA_CLDR_HI = 0;
|
||||||
|
|
||||||
|
if (pata_wait_ready_not_busy()) {
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark that the drive is initialized and present
|
||||||
|
g_pata_status = PATA_STAT_PRESENT;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read a block from the PATA hard drive
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// lba = the logical block address of the block to read
|
||||||
|
// buffer = the buffer into which to copy the block data
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of chars read, any negative number is an error code
|
||||||
|
//
|
||||||
|
short pata_read(long lba, unsigned char * buffer, short size) {
|
||||||
|
short i;
|
||||||
|
unsigned short *wptr;
|
||||||
|
TRACE("pata_read");
|
||||||
|
log_num(LOG_VERBOSE, "pata_read lba: ", lba);
|
||||||
|
|
||||||
|
/* Turn on the HDD LED */
|
||||||
|
ind_set(IND_HDC, IND_ON);
|
||||||
|
|
||||||
|
if (pata_wait_ready_not_busy()) {
|
||||||
|
/* Turn off the HDD LED */
|
||||||
|
ind_set(IND_HDC, IND_OFF);
|
||||||
|
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*PATA_HEAD = ((lba >> 24) & 0x07) | 0xe0; // Upper 3 bits of LBA, Drive 0, LBA mode.
|
||||||
|
if (pata_wait_ready_not_busy()) {
|
||||||
|
/* Turn off the HDD LED */
|
||||||
|
ind_set(IND_HDC, IND_OFF);
|
||||||
|
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*PATA_SECT_CNT = 1; // Read one sector (make this an option?)
|
||||||
|
*PATA_SECT_SRT = lba & 0xff; // Set the rest of the LBA
|
||||||
|
*PATA_CLDR_LO = (lba >> 8) & 0xff;
|
||||||
|
*PATA_CLDR_HI = (lba >> 16) & 0xff;
|
||||||
|
|
||||||
|
*PATA_CMD_STAT = PATA_CMD_READ_SECTOR; // Issue the READ command 0xE4; //
|
||||||
|
|
||||||
|
// TODO: Wait ~500ns
|
||||||
|
|
||||||
|
if (pata_wait_ready_not_busy()) {
|
||||||
|
/* Turn off the HDD LED */
|
||||||
|
ind_set(IND_HDC, IND_OFF);
|
||||||
|
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pata_wait_data_request()) {
|
||||||
|
/* Turn off the HDD LED */
|
||||||
|
ind_set(IND_HDC, IND_OFF);
|
||||||
|
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the data... let the compiler and the FPGA worry about endianess
|
||||||
|
for (i = 0, wptr = (unsigned short *)buffer; i < size; i += 2) {
|
||||||
|
*wptr++ = *PATA_DATA_16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn off the HDD LED */
|
||||||
|
ind_set(IND_HDC, IND_OFF);
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
short pata_flush_cache() {
|
||||||
|
long target_ticks;
|
||||||
|
short i;
|
||||||
|
unsigned short *wptr;
|
||||||
|
unsigned char status;
|
||||||
|
TRACE("pata_write");
|
||||||
|
|
||||||
|
if (pata_wait_ready_not_busy()) {
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*PATA_HEAD = 0xe0; // Drive 0
|
||||||
|
|
||||||
|
if (pata_wait_ready_not_busy()) {
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*PATA_SECT_SRT = 0; // Set the rest of the LBA
|
||||||
|
*PATA_CLDR_LO = 0;
|
||||||
|
*PATA_CLDR_HI = 0;
|
||||||
|
|
||||||
|
if (pata_wait_ready_not_busy()) {
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*PATA_CMD_STAT = 0xE7; // PATA_CMD_FLUSH_CACHE;
|
||||||
|
|
||||||
|
// Give the controller some time (100ms?)...
|
||||||
|
target_ticks = rtc_get_jiffies() + PATA_WAIT_JF;
|
||||||
|
while (target_ticks > rtc_get_jiffies()) ;
|
||||||
|
|
||||||
|
if (pata_wait_ready_not_busy()) {
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = *PATA_CMD_STAT;
|
||||||
|
if ((status & PATA_STAT_DF) != 0){
|
||||||
|
log(LOG_ERROR, "pata_flush_cache: device fault");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status & PATA_STAT_ERR) != 0) {
|
||||||
|
log(LOG_ERROR, "pata_flush_cache: error");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write a block to the PATA hard drive
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// lba = the logical block address of the block to write
|
||||||
|
// buffer = the buffer containing the data to write
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of chars written, any negative number is an error code
|
||||||
|
//
|
||||||
|
short pata_write(long lba, const unsigned char * buffer, short size) {
|
||||||
|
long target_ticks;
|
||||||
|
short i;
|
||||||
|
unsigned short *wptr;
|
||||||
|
unsigned char status;
|
||||||
|
TRACE("pata_write");
|
||||||
|
|
||||||
|
/* Turn on the HDD LED */
|
||||||
|
ind_set(IND_HDC, IND_ON);
|
||||||
|
|
||||||
|
if (pata_wait_ready_not_busy()) {
|
||||||
|
/* Turn off the HDD LED */
|
||||||
|
ind_set(IND_HDC, IND_OFF);
|
||||||
|
log(LOG_ERROR, "pata_write: pata_wait_ready_not_busy timeout 1");
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*PATA_HEAD = ((lba >> 24) & 0x07) | 0xe0; // Upper 3 bits of LBA, Drive 0, LBA mode.
|
||||||
|
|
||||||
|
if (pata_wait_ready_not_busy()) {
|
||||||
|
/* Turn off the HDD LED */
|
||||||
|
ind_set(IND_HDC, IND_OFF);
|
||||||
|
log(LOG_ERROR, "pata_write: pata_wait_ready_not_busy timeout 2");
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*PATA_SECT_CNT = 1; // Read one sector (make this an option?)
|
||||||
|
*PATA_SECT_SRT = lba & 0xff; // Set the rest of the LBA
|
||||||
|
*PATA_CLDR_LO = (lba >> 8) & 0xff;
|
||||||
|
*PATA_CLDR_HI = (lba >> 16) & 0xff;
|
||||||
|
|
||||||
|
*PATA_CMD_STAT = PATA_CMD_WRITE_SECTOR; // Issue the WRITE command
|
||||||
|
|
||||||
|
// Give the controller some time (100ms?)...
|
||||||
|
target_ticks = rtc_get_jiffies() + PATA_WAIT_JF;
|
||||||
|
while (target_ticks > rtc_get_jiffies()) ;
|
||||||
|
|
||||||
|
if (pata_wait_ready_not_busy()) {
|
||||||
|
/* Turn off the HDD LED */
|
||||||
|
ind_set(IND_HDC, IND_OFF);
|
||||||
|
log(LOG_ERROR, "pata_write: pata_wait_ready_not_busy timeout 3");
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the data... let the compiler and the FPGA worry about endianess
|
||||||
|
for (i = 0, wptr = (unsigned short *)buffer; i < size; i += 2) {
|
||||||
|
*PATA_DATA_16 = *wptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Give the controller some time...
|
||||||
|
// for (i = 0; i < 32000; i++) ;
|
||||||
|
|
||||||
|
if (pata_wait_ready_not_busy()) {
|
||||||
|
/* Turn off the HDD LED */
|
||||||
|
ind_set(IND_HDC, IND_OFF);
|
||||||
|
log(LOG_ERROR, "pata_write: pata_wait_ready_not_busy timeout 4");
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give the controller some time...
|
||||||
|
// for (i = 0; i < 32000; i++) ;
|
||||||
|
|
||||||
|
status = *PATA_CMD_STAT;
|
||||||
|
if ((status & PATA_STAT_DF) != 0){
|
||||||
|
log(LOG_ERROR, "pata_write: device fault");
|
||||||
|
|
||||||
|
/* Turn off the HDD LED */
|
||||||
|
ind_set(IND_HDC, IND_OFF);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((status & PATA_STAT_ERR) != 0) {
|
||||||
|
log(LOG_ERROR, "pata_write: error");
|
||||||
|
|
||||||
|
/* Turn off the HDD LED */
|
||||||
|
ind_set(IND_HDC, IND_OFF);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn off the HDD LED */
|
||||||
|
ind_set(IND_HDC, IND_OFF);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return the status of the PATA hard drive
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// the status of the device
|
||||||
|
//
|
||||||
|
short pata_status() {
|
||||||
|
TRACE("pata_status");
|
||||||
|
return g_pata_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return any error code of the PATA hard drive
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// the error code of the device
|
||||||
|
//
|
||||||
|
short pata_error() {
|
||||||
|
TRACE("pata_error");
|
||||||
|
return g_pata_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ensure that any pending writes to teh device have been completed
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
short pata_flush() {
|
||||||
|
TRACE("pata_flush");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Issue a control command to the PATA hard drive
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// command = the number of the command to send
|
||||||
|
// buffer = pointer to chars of additional data for the command
|
||||||
|
// size = the size of the buffer
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
short pata_ioctrl(short command, unsigned char * buffer, short size) {
|
||||||
|
short result;
|
||||||
|
long *p_long;
|
||||||
|
unsigned short *p_word;
|
||||||
|
long *p_lba_word;
|
||||||
|
t_drive_info drive_info;
|
||||||
|
p_drive_info p_info;
|
||||||
|
|
||||||
|
TRACE("pata_ioctrl");
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case PATA_GET_SECTOR_COUNT:
|
||||||
|
p_lba_word = (long *)buffer;
|
||||||
|
result = pata_identity(&drive_info);
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
*p_lba_word = drive_info.l.lba_default;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PATA_GET_SECTOR_SIZE:
|
||||||
|
// Return the size of a sector... always 512
|
||||||
|
p_word = (unsigned short *)buffer;
|
||||||
|
*p_word = PATA_SECTOR_SIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PATA_GET_BLOCK_SIZE:
|
||||||
|
// This isn't a flash device... return 1
|
||||||
|
p_long = (long *)buffer;
|
||||||
|
*p_long = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PATA_GET_DRIVE_INFO:
|
||||||
|
p_info = (p_drive_info)buffer;
|
||||||
|
result = pata_identity(p_info);
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Install the PATA driver
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
short pata_install() {
|
||||||
|
t_dev_block bdev;
|
||||||
|
|
||||||
|
TRACE("pata_install");
|
||||||
|
|
||||||
|
g_pata_error = 0;
|
||||||
|
g_pata_status = PATA_STAT_NOINIT;
|
||||||
|
|
||||||
|
// Check if drive is installed
|
||||||
|
// if ((*DIP_BOOTMODE & HD_INSTALLED) == 0) {
|
||||||
|
bdev.number = BDEV_HDC;
|
||||||
|
bdev.name = "HDD";
|
||||||
|
bdev.init = pata_init;
|
||||||
|
bdev.read = pata_read;
|
||||||
|
bdev.write = pata_write;
|
||||||
|
bdev.status = pata_status;
|
||||||
|
bdev.flush = pata_flush;
|
||||||
|
bdev.ioctrl = pata_ioctrl;
|
||||||
|
|
||||||
|
g_pata_status = PATA_STAT_PRESENT & PATA_STAT_NOINIT;
|
||||||
|
|
||||||
|
return bdev_register(&bdev);
|
||||||
|
// } else {
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
}
|
119
src/dev/pata.h
Normal file
119
src/dev/pata.h
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
/**
|
||||||
|
* Low level driver for the PATA hard drive.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PATA_H
|
||||||
|
#define __PATA_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "sys_types.h"
|
||||||
|
|
||||||
|
#define PATA_GET_SECTOR_COUNT 1
|
||||||
|
#define PATA_GET_SECTOR_SIZE 2
|
||||||
|
#define PATA_GET_BLOCK_SIZE 3
|
||||||
|
#define PATA_GET_DRIVE_INFO 4
|
||||||
|
|
||||||
|
#define PATA_SECTOR_SIZE 512 // Size of a block on the PATA
|
||||||
|
|
||||||
|
#define PATA_STAT_NOINIT 0x01 // PATA hard drive has not been initialized
|
||||||
|
#define PATA_STAT_PRESENT 0x02 // PATA hard drive is present
|
||||||
|
|
||||||
|
//
|
||||||
|
// Structures
|
||||||
|
//
|
||||||
|
|
||||||
|
typedef struct s_drive_info {
|
||||||
|
uint16_t flags;
|
||||||
|
char serial_number[18];
|
||||||
|
char firmware_version[6];
|
||||||
|
char model_name[38];
|
||||||
|
uint16_t lba_enabled;
|
||||||
|
union u1 {
|
||||||
|
struct s1 {
|
||||||
|
uint16_t lba_default_lo;
|
||||||
|
uint16_t lba_default_hi;
|
||||||
|
} lbaw;
|
||||||
|
uint32_t lba_default;
|
||||||
|
} l;
|
||||||
|
} t_drive_info, *p_drive_info;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Install the PATA driver
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern short pata_install();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the PATA hard drive
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern short pata_init();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read a block from the PATA hard drive
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// lba = the logical block address of the block to read
|
||||||
|
// buffer = the buffer into which to copy the block data
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of chars read, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern short pata_read(long lba, unsigned char * buffer, short size);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write a block to the PATA hard drive
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// lba = the logical block address of the block to write
|
||||||
|
// buffer = the buffer containing the data to write
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of chars written, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern short pata_write(long lba, const unsigned char * buffer, short size);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return the status of the PATA hard drive
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// the status of the device
|
||||||
|
//
|
||||||
|
extern short pata_status();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return any error code of the PATA hard drive
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// the error code of the device
|
||||||
|
//
|
||||||
|
extern short pata_error();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ensure that any pending writes to teh device have been completed
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern short pata_flush();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Issue a control command to the PATA hard drive
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// command = the number of the command to send
|
||||||
|
// buffer = pointer to chars of additional data for the command
|
||||||
|
// size = the size of the buffer
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern short pata_ioctrl(short command, unsigned char * buffer, short size);
|
||||||
|
|
||||||
|
#endif
|
1352
src/dev/ps2.c
Normal file
1352
src/dev/ps2.c
Normal file
File diff suppressed because it is too large
Load diff
89
src/dev/ps2.h
Normal file
89
src/dev/ps2.h
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/**
|
||||||
|
* Definitions for PS/2 interface mouse and keyboard.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PS2_H
|
||||||
|
#define __PS2_H
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
#include "sys_macros.h"
|
||||||
|
#include "sys_types.h"
|
||||||
|
#include "ps2_reg.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ps2_init status code flags
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PS2_FAIL_SELFTEST -1
|
||||||
|
#define PS2_FAIL_KBDTEST -2
|
||||||
|
|
||||||
|
#define PS2_KBD_MISSING 0x0001
|
||||||
|
#define PS2_MOUSE_MISSING 0x0002
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the PS2 controller and any attached devices
|
||||||
|
* Enable keyboard and mouse interrupts as appropriate.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* Status code indicating if either the mouse or the keyboard is missing.
|
||||||
|
*/
|
||||||
|
extern short ps2_init();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to retrieve the next scancode from the keyboard.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* The next scancode to be processed, 0 if nothing.
|
||||||
|
*/
|
||||||
|
extern unsigned short kbd_get_scancode();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to get a character from the keyboard...
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the next character to be read from the keyboard (0 if none available)
|
||||||
|
*/
|
||||||
|
extern char kbd_getc();
|
||||||
|
|
||||||
|
extern char kbd_getc_poll();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the keyboard translation tables
|
||||||
|
*
|
||||||
|
* The translation tables provided to the keyboard consist of eight
|
||||||
|
* consecutive tables of 128 characters each. Each table maps from
|
||||||
|
* the MAKE scan code of a key to its appropriate 8-bit character code.
|
||||||
|
*
|
||||||
|
* The tables included must include, in order:
|
||||||
|
* - UNMODIFIED: Used when no modifier keys are pressed or active
|
||||||
|
* - SHIFT: Used when the SHIFT modifier is pressed
|
||||||
|
* - CTRL: Used when the CTRL modifier is pressed
|
||||||
|
* - CTRL-SHIFT: Used when both CTRL and SHIFT are pressed
|
||||||
|
* - CAPSLOCK: Used when CAPSLOCK is down but SHIFT is not pressed
|
||||||
|
* - CAPSLOCK-SHIFT: Used when CAPSLOCK is down and SHIFT is pressed
|
||||||
|
* - ALT: Used when only ALT is presse
|
||||||
|
* - ALT-SHIFT: Used when ALT is pressed and either CAPSLOCK is down
|
||||||
|
* or SHIFT is pressed (but not both)
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* tables = pointer to the keyboard translation tables
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short kbd_layout(const char * tables);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Query the mouse for an update packet (use if we aren't using interrupts)
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
extern short ps2_mouse_get_packet();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the visibility of the VICKY mouse pointer
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* is_visible = 0 for hide, any other value to show
|
||||||
|
*/
|
||||||
|
extern void mouse_set_visible(short is_visible);
|
||||||
|
|
||||||
|
#endif
|
264
src/dev/rtc.c
Normal file
264
src/dev/rtc.c
Normal file
|
@ -0,0 +1,264 @@
|
||||||
|
/*
|
||||||
|
* Definitions for access the bq4802LY real time clock
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "interrupt.h"
|
||||||
|
#include "gabe_reg.h"
|
||||||
|
#include "rtc.h"
|
||||||
|
#include "rtc_reg.h"
|
||||||
|
#include "simpleio.h"
|
||||||
|
#include "timers.h"
|
||||||
|
|
||||||
|
static long rtc_ticks;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupt handler for the real time clock
|
||||||
|
*/
|
||||||
|
void rtc_handle_int() {
|
||||||
|
unsigned char flags;
|
||||||
|
|
||||||
|
/* Periodic interrupt: increment the ticks counter */
|
||||||
|
flags = *RTC_FLAGS;
|
||||||
|
rtc_ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the RTC
|
||||||
|
*/
|
||||||
|
void rtc_init() {
|
||||||
|
unsigned char flags;
|
||||||
|
unsigned char rates;
|
||||||
|
unsigned char enables;
|
||||||
|
|
||||||
|
log(LOG_TRACE, "rtc_init");
|
||||||
|
|
||||||
|
int_disable(INT_RTC);
|
||||||
|
|
||||||
|
/* Make sure the RTC is on */
|
||||||
|
*RTC_CTRL = (*RTC_CTRL & 0x07) | RTC_STOP;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For the moment: Every so often, the RTC interrupt gets acknowledged
|
||||||
|
* without clearing the flags. Until I can sort out why, I will use
|
||||||
|
* the SOF A interrupt as a surrogate for the RTC jiffie timer
|
||||||
|
*/
|
||||||
|
|
||||||
|
// /* Set the periodic interrupt to 15 millisecs */
|
||||||
|
// *RTC_RATES = RTC_RATE_15ms;
|
||||||
|
//
|
||||||
|
// int_register(INT_RTC, rtc_handle_int);
|
||||||
|
//
|
||||||
|
// /* Enable the periodic interrupt */
|
||||||
|
// flags = *RTC_FLAGS;
|
||||||
|
// *RTC_ENABLES = RTC_PIE;
|
||||||
|
// rtc_ticks = 0;
|
||||||
|
//
|
||||||
|
// int_enable(INT_RTC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure the RTC tick counter is enabled
|
||||||
|
*/
|
||||||
|
void rtc_enable_ticks() {
|
||||||
|
/* Set the periodic interrupt to 15 millisecs */
|
||||||
|
*RTC_RATES = RTC_RATE_15ms;
|
||||||
|
|
||||||
|
unsigned char flags = *RTC_FLAGS;
|
||||||
|
|
||||||
|
*RTC_ENABLES = RTC_PIE;
|
||||||
|
|
||||||
|
int_enable(INT_RTC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a function to be called periodically
|
||||||
|
*
|
||||||
|
* @param rate the rate at which the function should be called using the bq4802LY periodic rate values (0 to disable)
|
||||||
|
* @param handler a pointer to a function from void to void to be called
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
short rtc_register_periodic(short rate, FUNC_V_2_V handler) {
|
||||||
|
if (rate == 0) {
|
||||||
|
int_disable(INT_RTC);
|
||||||
|
*RTC_RATES = 0;
|
||||||
|
*RTC_ENABLES &= ~RTC_PIE;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
int_register(INT_RTC, handler);
|
||||||
|
*RTC_RATES = rate;
|
||||||
|
unsigned char flags = *RTC_FLAGS;
|
||||||
|
*RTC_ENABLES = RTC_PIE;
|
||||||
|
int_enable(INT_RTC);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the time on the RTC
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* time = pointer to a t_time record containing the correct time
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void rtc_set_time(p_time time) {
|
||||||
|
unsigned char ctrl;
|
||||||
|
unsigned char century_bcd, year_bcd, month_bcd, day_bcd;
|
||||||
|
unsigned char hour_bcd, minute_bcd, second_bcd;
|
||||||
|
unsigned short century;
|
||||||
|
unsigned short year;
|
||||||
|
|
||||||
|
century = time->year / 100;
|
||||||
|
year = time->year - (century * 100);
|
||||||
|
|
||||||
|
/* Compute the BCD values for the time */
|
||||||
|
|
||||||
|
century_bcd = i_to_bcd(century);
|
||||||
|
year_bcd = i_to_bcd(year);
|
||||||
|
month_bcd = i_to_bcd(time->month);
|
||||||
|
day_bcd = i_to_bcd(time->day);
|
||||||
|
hour_bcd = i_to_bcd(time->hour);
|
||||||
|
minute_bcd = i_to_bcd(time->minute);
|
||||||
|
second_bcd = i_to_bcd(time->second);
|
||||||
|
|
||||||
|
log_num(LOG_INFO, "Century: ", century_bcd);
|
||||||
|
log_num(LOG_INFO, "Year: ", year_bcd);
|
||||||
|
log_num(LOG_INFO, "Month: ", month_bcd);
|
||||||
|
log_num(LOG_INFO, "Day: ", day_bcd);
|
||||||
|
log_num(LOG_INFO, "Hour: ", hour_bcd);
|
||||||
|
log_num(LOG_INFO, "Minute: ", minute_bcd);
|
||||||
|
log_num(LOG_INFO, "Second: ", second_bcd);
|
||||||
|
|
||||||
|
if (!time->is_24hours) {
|
||||||
|
if (time->is_pm) {
|
||||||
|
hour_bcd = hour_bcd | 0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
minute_bcd = i_to_bcd(time->minute);
|
||||||
|
second_bcd = i_to_bcd(time->second);
|
||||||
|
|
||||||
|
/* Temporarily disable updates to the clock */
|
||||||
|
ctrl = *RTC_CTRL;
|
||||||
|
*RTC_CTRL = ctrl | RTC_UTI;
|
||||||
|
log(LOG_INFO, "RTC Disabled");
|
||||||
|
log_num(LOG_INFO, "RTC Rates: ", *RTC_RATES);
|
||||||
|
log_num(LOG_INFO, "RTC Enables: ", *RTC_ENABLES);
|
||||||
|
log_num(LOG_INFO, "RTC Flags: ", *RTC_FLAGS);
|
||||||
|
log_num(LOG_INFO, "RTC Control: ", *RTC_CTRL);
|
||||||
|
|
||||||
|
/* Set the time in the RTC */
|
||||||
|
|
||||||
|
*RTC_CENTURY = century_bcd;
|
||||||
|
*RTC_YEAR = year_bcd;
|
||||||
|
*RTC_MONTH = month_bcd;
|
||||||
|
*RTC_DAY = day_bcd;
|
||||||
|
*RTC_HOUR = hour_bcd;
|
||||||
|
*RTC_MIN = minute_bcd;
|
||||||
|
*RTC_SEC = second_bcd;
|
||||||
|
|
||||||
|
/* Verify */
|
||||||
|
|
||||||
|
century_bcd = *RTC_CENTURY;
|
||||||
|
year_bcd = *RTC_YEAR;
|
||||||
|
month_bcd = *RTC_MONTH;
|
||||||
|
day_bcd = *RTC_DAY;
|
||||||
|
hour_bcd = *RTC_HOUR;
|
||||||
|
minute_bcd = *RTC_MIN;
|
||||||
|
second_bcd = *RTC_SEC;
|
||||||
|
log_num(LOG_INFO, "REG Century: ", century_bcd);
|
||||||
|
log_num(LOG_INFO, "REG Year: ", year_bcd);
|
||||||
|
log_num(LOG_INFO, "REG Month: ", month_bcd);
|
||||||
|
log_num(LOG_INFO, "REG Day: ", day_bcd);
|
||||||
|
log_num(LOG_INFO, "REG Hour: ", hour_bcd);
|
||||||
|
log_num(LOG_INFO, "REG Minute: ", minute_bcd);
|
||||||
|
log_num(LOG_INFO, "REG Second: ", second_bcd);
|
||||||
|
|
||||||
|
/* Set the 24/12 hour control bit if needed */
|
||||||
|
if (time->is_24hours) {
|
||||||
|
ctrl = ctrl | RTC_2412;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Re-enable updates to the clock */
|
||||||
|
*RTC_CTRL = (ctrl & 0x07) | RTC_STOP;
|
||||||
|
log(LOG_INFO, "RTC Enabled");
|
||||||
|
log_num(LOG_INFO, "RTC Rates: ", *RTC_RATES);
|
||||||
|
log_num(LOG_INFO, "RTC Enables: ", *RTC_ENABLES);
|
||||||
|
log_num(LOG_INFO, "RTC Flags: ", *RTC_FLAGS);
|
||||||
|
log_num(LOG_INFO, "RTC Control: ", *RTC_CTRL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the time on the RTC
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* time = pointer to a t_time record in which to put the current time
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void rtc_get_time(p_time time) {
|
||||||
|
unsigned char ctrl;
|
||||||
|
unsigned char century_bcd, year_bcd, month_bcd, day_bcd;
|
||||||
|
unsigned char hour_bcd, minute_bcd, second_bcd;
|
||||||
|
|
||||||
|
/* Temporarily disable updates to the clock */
|
||||||
|
ctrl = *RTC_CTRL;
|
||||||
|
*RTC_CTRL = ctrl | RTC_UTI;
|
||||||
|
log(LOG_INFO, "RTC Disabled");
|
||||||
|
log_num(LOG_INFO, "RTC Rates: ", *RTC_RATES);
|
||||||
|
log_num(LOG_INFO, "RTC Enables: ", *RTC_ENABLES);
|
||||||
|
log_num(LOG_INFO, "RTC Flags: ", *RTC_FLAGS);
|
||||||
|
log_num(LOG_INFO, "RTC Control: ", *RTC_CTRL);
|
||||||
|
|
||||||
|
if (*RTC_CTRL & RTC_2412) {
|
||||||
|
time->is_24hours = 1;
|
||||||
|
} else {
|
||||||
|
time->is_24hours = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
century_bcd = *RTC_CENTURY;
|
||||||
|
year_bcd = *RTC_YEAR;
|
||||||
|
month_bcd = *RTC_MONTH;
|
||||||
|
day_bcd = *RTC_DAY;
|
||||||
|
hour_bcd = *RTC_HOUR;
|
||||||
|
minute_bcd = *RTC_MIN;
|
||||||
|
second_bcd = *RTC_SEC;
|
||||||
|
|
||||||
|
/* Re-enable updates to the clock */
|
||||||
|
*RTC_CTRL = (ctrl & 0x07) | RTC_STOP;
|
||||||
|
log(LOG_INFO, "RTC Enabled");
|
||||||
|
log_num(LOG_INFO, "RTC Rates: ", *RTC_RATES);
|
||||||
|
log_num(LOG_INFO, "RTC Enables: ", *RTC_ENABLES);
|
||||||
|
log_num(LOG_INFO, "RTC Flags: ", *RTC_FLAGS);
|
||||||
|
log_num(LOG_INFO, "RTC Control: ", *RTC_CTRL);
|
||||||
|
|
||||||
|
log_num(LOG_INFO, "Century: ", century_bcd);
|
||||||
|
log_num(LOG_INFO, "Year: ", year_bcd);
|
||||||
|
log_num(LOG_INFO, "Month: ", month_bcd);
|
||||||
|
log_num(LOG_INFO, "Day: ", day_bcd);
|
||||||
|
log_num(LOG_INFO, "Hour: ", hour_bcd);
|
||||||
|
log_num(LOG_INFO, "Minute: ", minute_bcd);
|
||||||
|
log_num(LOG_INFO, "Second: ", second_bcd);
|
||||||
|
|
||||||
|
/* Fill out the time record */
|
||||||
|
|
||||||
|
time->year = bcd_to_i(century_bcd) * 100 + bcd_to_i(year_bcd);
|
||||||
|
time->month = bcd_to_i(month_bcd);
|
||||||
|
time->day = bcd_to_i(day_bcd);
|
||||||
|
time->hour = bcd_to_i(hour_bcd & 0x7f);
|
||||||
|
time->is_pm = ((hour_bcd & 0x80) == 0x80) ? 1 : 0;
|
||||||
|
time->minute = bcd_to_i(minute_bcd);
|
||||||
|
time->second = bcd_to_i(second_bcd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the number of jiffies since the system last booted.
|
||||||
|
*
|
||||||
|
* NOTE: a jiffie is 1/60 of a second. This timer will not be
|
||||||
|
* 100% precise, so it should be used for timeout purposes
|
||||||
|
* where precision is not critical.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the number of jiffies since the last reset
|
||||||
|
*/
|
||||||
|
long rtc_get_jiffies() {
|
||||||
|
return timers_jiffies();
|
||||||
|
}
|
||||||
|
|
58
src/dev/rtc.h
Normal file
58
src/dev/rtc.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Declarations for access the bq4802LY real time clock
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RTC_H
|
||||||
|
#define __RTC_H
|
||||||
|
|
||||||
|
#include "sys_macros.h"
|
||||||
|
#include "sys_types.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the RTC
|
||||||
|
*/
|
||||||
|
extern void rtc_init();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure the RTC tick counter is enabled
|
||||||
|
*/
|
||||||
|
extern void rtc_enable_ticks();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the time on the RTC
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* time = pointer to a t_time record containing the correct time
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL void rtc_set_time(p_time time);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the time on the RTC
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* time = pointer to a t_time record in which to put the current time
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL void rtc_get_time(p_time time);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the number of jiffies since the system last booted.
|
||||||
|
*
|
||||||
|
* NOTE: a jiffie is 1/60 of a second. This timer will not be
|
||||||
|
* 100% precise, so it should be used for timeout purposes
|
||||||
|
* where precision is not critical.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the number of jiffies since the last reset
|
||||||
|
*/
|
||||||
|
extern long rtc_get_jiffies();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a function to be called periodically
|
||||||
|
*
|
||||||
|
* @param rate the rate at which the function should be called using the bq4802LY periodic rate values (0 to disable)
|
||||||
|
* @param handler a pointer to a function from void to void to be called
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
extern short rtc_register_periodic(short rate, FUNC_V_2_V handler);
|
||||||
|
|
||||||
|
#endif
|
442
src/dev/sdc.c
Normal file
442
src/dev/sdc.c
Normal file
|
@ -0,0 +1,442 @@
|
||||||
|
/**
|
||||||
|
* Implementation of the SDC device driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "log_level.h"
|
||||||
|
#ifndef DEFAULT_LOG_LEVEL
|
||||||
|
#define DEFAULT_LOG_LEVEL LOG_INFO
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "errors.h"
|
||||||
|
#include "gabe_reg.h"
|
||||||
|
#include "indicators.h"
|
||||||
|
#include "interrupt.h"
|
||||||
|
#include "dev/block.h"
|
||||||
|
#include "sdc_reg.h"
|
||||||
|
#include "dev/rtc.h"
|
||||||
|
#include "dev/sdc.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// Constants
|
||||||
|
//
|
||||||
|
|
||||||
|
#define SDC_TIMEOUT_JF 20 /* Timeout in jiffies (1/60 second) */
|
||||||
|
|
||||||
|
unsigned char g_sdc_status = SDC_STAT_NOINIT;
|
||||||
|
unsigned char g_sdc_error = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle insertion of an SD card
|
||||||
|
*/
|
||||||
|
void sdc_handler() {
|
||||||
|
/* Very simple... just flag it as uninitialized */
|
||||||
|
g_sdc_status = SDC_STAT_NOINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Attempt to reset the SD controller
|
||||||
|
//
|
||||||
|
void sdc_reset() {
|
||||||
|
short delay;
|
||||||
|
|
||||||
|
TRACE("sdc_reset");
|
||||||
|
|
||||||
|
// NOTE: I haven't quite figured out reset on this block... setting the reset bit
|
||||||
|
// seems to leave the controller in an odd state.
|
||||||
|
|
||||||
|
// *SDC_CONTROL_REG = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return true if there is an SD card in the slot
|
||||||
|
//
|
||||||
|
short sdc_detected() {
|
||||||
|
TRACE("sdc_detected()");
|
||||||
|
return (*GABE_SDC_REG & GABE_SDC_PRESENT) != GABE_SDC_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return true if there is an SD card is protected
|
||||||
|
//
|
||||||
|
short sdc_protected() {
|
||||||
|
TRACE("sdc_protected()");
|
||||||
|
return (*GABE_SDC_REG & GABE_SDC_WPROT) == GABE_SDC_WPROT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Turn the SDC LED on or off
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// is_on = if 0, turn the LED off, otherwise turn the LED on
|
||||||
|
//
|
||||||
|
void sdc_set_led(short is_on) {
|
||||||
|
ind_set(IND_SDC, is_on);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Wait for the SDC to complete its transaction
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, DEV_TIMEOUT on timeout
|
||||||
|
//
|
||||||
|
short sdc_wait_busy() {
|
||||||
|
long timer_ticks;
|
||||||
|
unsigned char status;
|
||||||
|
|
||||||
|
timer_ticks = rtc_get_jiffies() + SDC_TIMEOUT_JF;
|
||||||
|
do {
|
||||||
|
if (rtc_get_jiffies() > timer_ticks) {
|
||||||
|
// If we have run out of tries, return a TIMEOUT error
|
||||||
|
TRACE("sdc_wait_busy: DEV_TIMEOUT");
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
status = *SDC_TRANS_STATUS_REG;
|
||||||
|
} while ((status & SDC_TRANS_BUSY) == SDC_TRANS_BUSY);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the SDC
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
short sdc_init() {
|
||||||
|
TRACE("sdc_init");
|
||||||
|
|
||||||
|
// Check for presence of the card
|
||||||
|
|
||||||
|
if (!sdc_detected()) {
|
||||||
|
// SDC_DETECTED is active 0... 1 means there is no card
|
||||||
|
g_sdc_status = SDC_STAT_NOINIT;
|
||||||
|
return DEV_NOMEDIA;
|
||||||
|
}
|
||||||
|
|
||||||
|
*SDC_TRANS_TYPE_REG = SDC_TRANS_INIT_SD; // Start the INIT_SD transaction
|
||||||
|
*SDC_TRANS_CONTROL_REG = SDC_TRANS_START;
|
||||||
|
|
||||||
|
if (sdc_wait_busy() == 0) { // Wait for it to complete
|
||||||
|
g_sdc_error = *SDC_TRANS_ERROR_REG; // Check for any error condition
|
||||||
|
if (g_sdc_error == 0) {
|
||||||
|
log(LOG_INFO, "sdc_init: SUCCESS");
|
||||||
|
g_sdc_status = 0; // Flag that the SD has been initialized
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log(LOG_ERROR, "sdc_init: DEV_CANNOT_INIT");
|
||||||
|
g_sdc_status = SDC_STAT_NOINIT;
|
||||||
|
return DEV_CANNOT_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log(LOG_ERROR, "sdc_init: DEV_TIMEOUT");
|
||||||
|
g_sdc_status = SDC_STAT_NOINIT;
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read a block from the SDC
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// lba = the logical block address of the block to read
|
||||||
|
// buffer = the buffer into which to copy the block data
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of bytes read, any negative number is an error code
|
||||||
|
//
|
||||||
|
short sdc_read(long lba, unsigned char * buffer, short size) {
|
||||||
|
long adjusted_lba;
|
||||||
|
|
||||||
|
TRACE3("sdc_read(%ld,%p,%d)", lba, buffer, (int)size);
|
||||||
|
|
||||||
|
// Check for presence of the card
|
||||||
|
|
||||||
|
if (!sdc_detected()) {
|
||||||
|
// SDC_DETECTED is active 0... 1 means there is no card
|
||||||
|
g_sdc_status = SDC_STAT_NOINIT;
|
||||||
|
TRACE("sdc_read: DEV_NOMEDIA");
|
||||||
|
return DEV_NOMEDIA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn on the SDC LED */
|
||||||
|
ind_set(IND_SDC, IND_ON);
|
||||||
|
|
||||||
|
// Send the LBA to the SDC
|
||||||
|
|
||||||
|
adjusted_lba = lba << 9;
|
||||||
|
*SDC_SD_ADDR_7_0_REG = adjusted_lba & 0xff;
|
||||||
|
*SDC_SD_ADDR_15_8_REG = (adjusted_lba >> 8) & 0xff;
|
||||||
|
*SDC_SD_ADDR_23_16_REG = (adjusted_lba >> 16) & 0xff;
|
||||||
|
*SDC_SD_ADDR_31_24_REG = (adjusted_lba >> 24) & 0xff;
|
||||||
|
|
||||||
|
// Start the READ transaction
|
||||||
|
|
||||||
|
*SDC_TRANS_TYPE_REG = SDC_TRANS_READ_BLK; // Set the transaction type to READ
|
||||||
|
*SDC_TRANS_CONTROL_REG = SDC_TRANS_START; // Start the transaction
|
||||||
|
|
||||||
|
if (sdc_wait_busy() == 0) { // Wait for the transaction to complete
|
||||||
|
g_sdc_error = *SDC_TRANS_ERROR_REG; // Check for errors
|
||||||
|
|
||||||
|
if (g_sdc_error != 0) {
|
||||||
|
/* Turn off the SDC LED */
|
||||||
|
ind_set(IND_SDC, IND_OFF);
|
||||||
|
TRACE("sdc_read: DEV_CANNOT_READ");
|
||||||
|
return DEV_CANNOT_READ;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
short count;
|
||||||
|
short i;
|
||||||
|
|
||||||
|
// Get the number of bytes to be read and make sure there is room
|
||||||
|
count = *SDC_RX_FIFO_DATA_CNT_HI << 8 | *SDC_RX_FIFO_DATA_CNT_LO;
|
||||||
|
if (count > size) {
|
||||||
|
/* Turn off the SDC LED */
|
||||||
|
ind_set(IND_SDC, IND_OFF);
|
||||||
|
TRACE("sdc_read: DEV_BOUNDS_ERR");
|
||||||
|
return DEV_BOUNDS_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) { // Fetch the bytes from the SDC
|
||||||
|
buffer[i] = *SDC_RX_FIFO_DATA_REG;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdc_set_led(0); // Turn off the SDC LED
|
||||||
|
|
||||||
|
g_sdc_error = *SDC_TRANS_ERROR_REG; // Check for errors
|
||||||
|
if (g_sdc_error != 0) {
|
||||||
|
/* Turn off the SDC LED */
|
||||||
|
ind_set(IND_SDC, IND_OFF);
|
||||||
|
TRACE("sdc_read: DEV_CANNOT_READ");
|
||||||
|
return DEV_CANNOT_READ;
|
||||||
|
} else {
|
||||||
|
/* Turn off the SDC LED */
|
||||||
|
ind_set(IND_SDC, IND_OFF);
|
||||||
|
|
||||||
|
// Success: return the byte count
|
||||||
|
TRACE1("sdc_read: returning %d", count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Turn off the SDC LED */
|
||||||
|
ind_set(IND_SDC, IND_OFF);
|
||||||
|
|
||||||
|
TRACE("sdc_read: DEV_TIMEOUT");
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write a block to the SDC
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// lba = the TRACEical block address of the block to write
|
||||||
|
// buffer = the buffer containing the data to write
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of bytes written, any negative number is an error code
|
||||||
|
//
|
||||||
|
short sdc_write(long lba, const unsigned char * buffer, short size) {
|
||||||
|
long adjusted_lba;
|
||||||
|
short i;
|
||||||
|
|
||||||
|
TRACE("sdc_write");
|
||||||
|
|
||||||
|
// Check for presence of the card
|
||||||
|
|
||||||
|
if (!sdc_detected()) {
|
||||||
|
// SDC_DETECTED is active 0... 1 means there is no card
|
||||||
|
g_sdc_status = SDC_STAT_NOINIT;
|
||||||
|
return DEV_NOMEDIA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn on the SDC LED */
|
||||||
|
ind_set(IND_SDC, IND_ON);
|
||||||
|
|
||||||
|
if (size <= SDC_SECTOR_SIZE) {
|
||||||
|
// Copy the data to the SDC, if there isn't too much...
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
*SDC_TX_FIFO_DATA_REG = buffer[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < SDC_SECTOR_SIZE) {
|
||||||
|
// If we copied less than a block's worth, pad the rest with 0s...
|
||||||
|
for (i = 0; i < SDC_SECTOR_SIZE - size; i++) {
|
||||||
|
*SDC_TX_FIFO_DATA_REG = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Turn off the SDC LED */
|
||||||
|
ind_set(IND_SDC, IND_OFF);
|
||||||
|
|
||||||
|
// If size is too big, return a BOUNDS error
|
||||||
|
return DEV_BOUNDS_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the LBA to the SDC
|
||||||
|
|
||||||
|
adjusted_lba = lba << 9;
|
||||||
|
*SDC_SD_ADDR_7_0_REG = adjusted_lba & 0xff;
|
||||||
|
*SDC_SD_ADDR_15_8_REG = (adjusted_lba >> 8) & 0xff;
|
||||||
|
*SDC_SD_ADDR_23_16_REG = (adjusted_lba >> 16) & 0xff;
|
||||||
|
*SDC_SD_ADDR_31_24_REG = (adjusted_lba >> 24) & 0xff;
|
||||||
|
|
||||||
|
// Start the WRITE transaction
|
||||||
|
|
||||||
|
*SDC_TRANS_TYPE_REG = SDC_TRANS_WRITE_BLK; // Set the transaction type to WRITE
|
||||||
|
*SDC_TRANS_CONTROL_REG = SDC_TRANS_START; // Start the transaction
|
||||||
|
|
||||||
|
if (sdc_wait_busy() == 0) { // Wait for the transaction to complete
|
||||||
|
g_sdc_error = *SDC_TRANS_ERROR_REG; // Check for errors
|
||||||
|
|
||||||
|
if (g_sdc_error != 0) {
|
||||||
|
/* Turn off the SDC LED */
|
||||||
|
ind_set(IND_SDC, IND_OFF);
|
||||||
|
|
||||||
|
return DEV_CANNOT_WRITE;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Turn off the SDC LED */
|
||||||
|
ind_set(IND_SDC, IND_OFF);
|
||||||
|
|
||||||
|
// Success: return the byte count
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Turn off the SDC LED */
|
||||||
|
ind_set(IND_SDC, IND_OFF);
|
||||||
|
|
||||||
|
return DEV_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return the status of the SDC
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// the status of the device
|
||||||
|
//
|
||||||
|
short sdc_status() {
|
||||||
|
short status = g_sdc_status;
|
||||||
|
|
||||||
|
TRACE1("sdc_status, status=0x%x",(int)status);
|
||||||
|
|
||||||
|
if (sdc_detected()) {
|
||||||
|
// Add the PRESENT flag, if the card is inserted
|
||||||
|
status |= SDC_STAT_PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdc_protected()) {
|
||||||
|
// Add the PROTECTED flag, if the card is write-protected
|
||||||
|
status |= SDC_STAT_PROTECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE1("sdc_status: %x", (short)status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return any error code of the SDC
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// the error code of the device
|
||||||
|
//
|
||||||
|
short sdc_error() {
|
||||||
|
return g_sdc_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ensure that any pending writes to teh device have been completed
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
short sdc_flush() {
|
||||||
|
return 0; // We don't buffer writes... always return success
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return the count of sectors in this SD card
|
||||||
|
//
|
||||||
|
short sdc_sector_count() {
|
||||||
|
// TODO: implement this!
|
||||||
|
return 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SDC_GET_SECTOR_COUNT 1
|
||||||
|
#define SDC_GET_SECTOR_SIZE 2
|
||||||
|
#define SDC_GET_BLOCK_SIZE 3
|
||||||
|
|
||||||
|
//
|
||||||
|
// Issue a control command to the device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// command = the number of the command to send
|
||||||
|
// buffer = pointer to bytes of additional data for the command
|
||||||
|
// size = the size of the buffer
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
short sdc_ioctrl(short command, unsigned char * buffer, short size) {
|
||||||
|
unsigned long *p_dword;
|
||||||
|
unsigned short *p_word;
|
||||||
|
unsigned long *p_lba_word;
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case SDC_GET_SECTOR_COUNT:
|
||||||
|
p_lba_word = (unsigned long *)buffer;
|
||||||
|
*p_lba_word = sdc_sector_count();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDC_GET_SECTOR_SIZE:
|
||||||
|
// Return the size of a sector... always 512
|
||||||
|
p_word = (unsigned short *)buffer;
|
||||||
|
*p_word = SDC_SECTOR_SIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDC_GET_BLOCK_SIZE:
|
||||||
|
// We don't know what the block size is... return 1
|
||||||
|
p_dword = (unsigned long *)buffer;
|
||||||
|
*p_dword = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Install the SDC driver
|
||||||
|
//
|
||||||
|
short sdc_install() {
|
||||||
|
t_dev_block dev; // bdev_register copies the data, so we'll allocate this on the stack
|
||||||
|
|
||||||
|
TRACE("sdc_install");
|
||||||
|
|
||||||
|
/* Install an interrupt handler to catch insertion of a card */
|
||||||
|
int_register(INT_SDC_INS, sdc_handler);
|
||||||
|
int_enable(INT_SDC_INS);
|
||||||
|
|
||||||
|
sdc_reset();
|
||||||
|
|
||||||
|
dev.number = BDEV_SDC;
|
||||||
|
dev.name = "SDC";
|
||||||
|
dev.init = sdc_init;
|
||||||
|
dev.read = sdc_read;
|
||||||
|
dev.write = sdc_write;
|
||||||
|
dev.flush = sdc_flush;
|
||||||
|
dev.status = sdc_status;
|
||||||
|
dev.ioctrl = sdc_ioctrl;
|
||||||
|
|
||||||
|
return bdev_register(&dev);
|
||||||
|
}
|
96
src/dev/sdc.h
Normal file
96
src/dev/sdc.h
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
/**
|
||||||
|
* Definitions support low level SDC device driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SDC_H
|
||||||
|
#define __SDC_H
|
||||||
|
|
||||||
|
#include "sys_types.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// Definitions for GABE's internal SD card controller
|
||||||
|
//
|
||||||
|
|
||||||
|
#define SDC_SECTOR_SIZE 512 // Size of a block on the SDC
|
||||||
|
|
||||||
|
#define SDC_STAT_NOINIT 0x01 // SD has not been initialized
|
||||||
|
#define SDC_STAT_PRESENT 0x02 // SD is present
|
||||||
|
#define SDC_STAT_PROTECTED 0x04 // SD is write-protected
|
||||||
|
|
||||||
|
//
|
||||||
|
// Install the SDC driver
|
||||||
|
//
|
||||||
|
extern short sdc_install();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the SDC
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern short sdc_init();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read a block from the SDC
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// lba = the logical block address of the block to read
|
||||||
|
// buffer = the buffer into which to copy the block data
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of bytes read, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern short sdc_read(long lba, unsigned char * buffer, short size);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write a block to the SDC
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// lba = the logical block address of the block to write
|
||||||
|
// buffer = the buffer containing the data to write
|
||||||
|
// size = the size of the buffer.
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// number of bytes written, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern short sdc_write(long lba, const unsigned char * buffer, short size);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return the status of the SDC
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// the status of the device
|
||||||
|
//
|
||||||
|
extern short sdc_status();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return any error code of the SDC
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// the error code of the device
|
||||||
|
//
|
||||||
|
extern short sdc_error();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ensure that any pending writes to teh device have been completed
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern short sdc_flush();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Issue a control command to the device
|
||||||
|
//
|
||||||
|
// Inputs:
|
||||||
|
// command = the number of the command to send
|
||||||
|
// buffer = pointer to bytes of additional data for the command
|
||||||
|
// size = the size of the buffer
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// 0 on success, any negative number is an error code
|
||||||
|
//
|
||||||
|
extern short sdc_ioctrl(short command, unsigned char * buffer, short size);
|
||||||
|
|
||||||
|
#endif
|
58
src/dev/timers_c256.c
Normal file
58
src/dev/timers_c256.c
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "interrupt.h"
|
||||||
|
#include "timers.h"
|
||||||
|
#include "gabe_reg.h"
|
||||||
|
#include "timers_reg.h"
|
||||||
|
|
||||||
|
long jiffy_count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Interrupt handler for the timer 0 interrupt... counts jiffies since boot
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void timer_0_handler() {
|
||||||
|
jiffy_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the timers and their interrupts
|
||||||
|
*/
|
||||||
|
void timers_init() {
|
||||||
|
// Number of system clock ticks per second
|
||||||
|
const uint32_t sys_clock = 14318180;
|
||||||
|
|
||||||
|
// Number of system clocks per jiffy
|
||||||
|
const uint32_t jiffy_target = sys_clock / (uint32_t)60;
|
||||||
|
|
||||||
|
jiffy_count = 0;
|
||||||
|
|
||||||
|
// Disable all timers
|
||||||
|
*TIMER_CTRL_0 = 0;
|
||||||
|
*TIMER_CTRL_1 = 0;
|
||||||
|
*TIMER_CTRL_2 = 0;
|
||||||
|
|
||||||
|
// Register our timer 0 interrupt handler
|
||||||
|
int_register(INT_SOF_A, timer_0_handler);
|
||||||
|
int_enable(INT_SOF_A);
|
||||||
|
|
||||||
|
// Set timer 0 to tick every jiffy
|
||||||
|
|
||||||
|
// *TIMER_CHG_L_0 = jiffy_target & 0xff;
|
||||||
|
// *TIMER_CHG_M_0 = (jiffy_target >> 8) & 0xff;
|
||||||
|
// *TIMER_CHG_H_0 = (jiffy_target >> 16) & 0xff;
|
||||||
|
|
||||||
|
// *TIMER_CMP_L_0 = 0;
|
||||||
|
// *TIMER_CMP_M_0 = 0;
|
||||||
|
// *TIMER_CMP_H_0 = 0;
|
||||||
|
|
||||||
|
// *TIMER_CMPC_0 = TIMER_CMP_RELOAD;
|
||||||
|
// *TIMER_CTRL_0 = TIMER_CTRL_EN | TIMER_CTRL_SLOAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the number of jiffies (1/60 of a second) since last reset time
|
||||||
|
*/
|
||||||
|
long timers_jiffies() {
|
||||||
|
return jiffy_count;
|
||||||
|
}
|
684
src/dev/txt_a2560k_a.c
Normal file
684
src/dev/txt_a2560k_a.c
Normal file
|
@ -0,0 +1,684 @@
|
||||||
|
/** @file txt_a2560k_a.c
|
||||||
|
*
|
||||||
|
* Text screen driver for A2560K Channel A
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "constants.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
#include "sys_general.h"
|
||||||
|
#include "A2560K/vky_chan_a.h"
|
||||||
|
#include "A2560K/vky_chan_b.h"
|
||||||
|
#include "dev/txt_screen.h"
|
||||||
|
#include "dev/txt_a2560k_a.h"
|
||||||
|
|
||||||
|
extern const unsigned char MSX_CP437_8x8_bin[];
|
||||||
|
|
||||||
|
/* Default text color lookup table values (AARRGGBB) */
|
||||||
|
const unsigned long a2560k_a_lut[VKY3_A_LUT_SIZE] = {
|
||||||
|
0xFF000000, // Black (transparent)
|
||||||
|
0xFF800000, // Mid-Tone Red
|
||||||
|
0xFF008000, // Mid-Tone Green
|
||||||
|
0xFF808000, // Mid-Tone Yellow
|
||||||
|
0xFF000080, // Mid-Tone Blue
|
||||||
|
0xFFAA5500, // Mid-Tone Orange
|
||||||
|
0xFF008080, // Mid-Tone Cian
|
||||||
|
0xFF808080, // 50% Grey
|
||||||
|
#if MODEL_FOENIX_A2560X
|
||||||
|
0xFF202020, // Dark Grey
|
||||||
|
#else
|
||||||
|
0xFF555555, // Dark Grey
|
||||||
|
#endif
|
||||||
|
0xFFFF0000, // Bright Red
|
||||||
|
0xFF55FF55, // Bright Green
|
||||||
|
0xFFFFFF55, // Bright Yellow
|
||||||
|
0xFF5555FF, // Bright Blue
|
||||||
|
0xFFFF7FFF, // Bright Orange
|
||||||
|
0xFF55FFFF, // Bright Cyan
|
||||||
|
0xFFFFFFFF // White
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver level variables for the screen
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned char a2560k_a_enable_set_sizes; /* Flag to enable set_sizes to actually do its computation */
|
||||||
|
t_txt_capabilities a2560k_a_caps; /* The capabilities of Channel A */
|
||||||
|
t_extent a2560k_a_resolutions[2]; /* The list of display resolutions */
|
||||||
|
t_extent a2560k_a_fonts[2]; /* The list of font resolutions */
|
||||||
|
t_rect a2560k_a_region; /* The current region */
|
||||||
|
t_point a2560k_a_cursor; /* The current cursor position */
|
||||||
|
t_extent a2560k_a_resolution; /* The current display resolution */
|
||||||
|
t_extent a2560k_a_font_size; /* The current font size */
|
||||||
|
t_extent a2560k_a_max_size; /* The size of the screen in characters (without border removed) */
|
||||||
|
t_extent a2560k_a_visible_size; /* The size of the visible screen in characters (with border removed) */
|
||||||
|
short a2560k_a_border_width; /* Width of the border on one side */
|
||||||
|
short a2560k_a_border_height; /* Height of the border on one side */
|
||||||
|
unsigned char a2560k_a_color; /* The current color */
|
||||||
|
unsigned long msr_shadow; /* A shadow register for the Master Control Register */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the description of a screen's capabilities
|
||||||
|
*
|
||||||
|
* @return a pointer to the read-only description (0 on error)
|
||||||
|
*/
|
||||||
|
const p_txt_capabilities txt_a2560k_a_get_capabilities() {
|
||||||
|
return &a2560k_a_caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the size of the text screen in rows and columns so that
|
||||||
|
* the kernel printing routines can work correctly.
|
||||||
|
*
|
||||||
|
* NOTE: this should be called whenever the VKY3 Channel A registers are changed
|
||||||
|
*/
|
||||||
|
void txt_a2560k_a_set_sizes() {
|
||||||
|
if (a2560k_a_enable_set_sizes) {
|
||||||
|
/* Only recalculate after initialization is mostly completed */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the maximum number of characters visible on the screen
|
||||||
|
* This controls text layout in memory
|
||||||
|
*/
|
||||||
|
a2560k_a_max_size.width = a2560k_a_resolution.width / a2560k_a_font_size.width;
|
||||||
|
a2560k_a_max_size.height = a2560k_a_resolution.height / a2560k_a_font_size.height;
|
||||||
|
|
||||||
|
// /* Set the font manager register */
|
||||||
|
*VKY3_A_FM1 = (a2560k_a_max_size.height & 0xff) << 8 | (a2560k_a_max_size.width & 0xff);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the characters that are visible in whole or in part
|
||||||
|
*/
|
||||||
|
if ((a2560k_a_border_width != 0) && (a2560k_a_border_height != 0)) {
|
||||||
|
short border_width = (2 * a2560k_a_border_width) / a2560k_a_font_size.width;
|
||||||
|
short border_height = (2 * a2560k_a_border_height) / a2560k_a_font_size.height;
|
||||||
|
a2560k_a_visible_size.width = a2560k_a_max_size.width - border_width;
|
||||||
|
a2560k_a_visible_size.height = a2560k_a_max_size.height - border_height;
|
||||||
|
} else {
|
||||||
|
a2560k_a_visible_size.width = a2560k_a_max_size.width;
|
||||||
|
a2560k_a_visible_size.height = a2560k_a_max_size.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the display resolutions
|
||||||
|
*
|
||||||
|
* @param text_size the size of the screen in visible characters (may be null)
|
||||||
|
* @param pixel_size the size of the screen in pixels (may be null)
|
||||||
|
*/
|
||||||
|
void txt_a2560k_a_get_sizes(p_extent text_size, p_extent pixel_size) {
|
||||||
|
if (text_size) {
|
||||||
|
text_size->width = a2560k_a_visible_size.width;
|
||||||
|
text_size->height = a2560k_a_visible_size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixel_size) {
|
||||||
|
pixel_size->width = a2560k_a_resolution.width;
|
||||||
|
pixel_size->height = a2560k_a_resolution.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the display mode for the screen
|
||||||
|
*
|
||||||
|
* @param mode a bitfield of desired display mode options
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the mode is invalid for the screen
|
||||||
|
*/
|
||||||
|
short txt_a2560k_a_set_mode(short mode) {
|
||||||
|
/* Turn off anything not set */
|
||||||
|
msr_shadow &= ~(TXT_MODE_SLEEP | TXT_MODE_TEXT);
|
||||||
|
|
||||||
|
if (mode & TXT_MODE_SLEEP) {
|
||||||
|
/* Put the monitor to sleep */
|
||||||
|
msr_shadow |= VKY3_A_MCR_SLEEP;
|
||||||
|
*VKY3_A_MCR = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else if (mode & TXT_MODE_TEXT) {
|
||||||
|
/* Put on text mode */
|
||||||
|
msr_shadow |= VKY3_A_MCR_TEXT;
|
||||||
|
*VKY3_A_MCR = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Unsupported mode */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the display resolution of the screen
|
||||||
|
*
|
||||||
|
* @param width the desired horizontal resolution in pixels
|
||||||
|
* @param height the desired veritical resolution in pixels
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the resolution is unsupported
|
||||||
|
*/
|
||||||
|
short txt_a2560k_a_set_resolution(short width, short height) {
|
||||||
|
// If no size specified, set it based on the DIP switch
|
||||||
|
if ((width == 0) || (height == 0)) {
|
||||||
|
if ((*VKY3_A_MCR & VKY3_A_HIRES) == 0) {
|
||||||
|
width = 1024;
|
||||||
|
height = 768;
|
||||||
|
} else {
|
||||||
|
width = 800;
|
||||||
|
height = 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kick the PLL
|
||||||
|
// If VICKY is generating a 40MHz signal, we need to switch the bit to go to 40MHz before
|
||||||
|
// clearing it to go back to 25MHz.
|
||||||
|
if (*VKY3_A_MCR & VKY3_A_CLK40) {
|
||||||
|
*VKY3_A_MCR |= VKY3_A_1024x768;
|
||||||
|
*VKY3_A_MCR &= ~(VKY3_A_1024x768);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn off resolution bits */
|
||||||
|
msr_shadow &= ~(VKY3_A_1024x768);
|
||||||
|
|
||||||
|
if ((width == 800) && (height == 600)) {
|
||||||
|
a2560k_a_resolution.width = width;
|
||||||
|
a2560k_a_resolution.height = height;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_a2560k_a_set_sizes();
|
||||||
|
|
||||||
|
*VKY3_A_MCR = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else if ((width == 1024) && (height == 768)) {
|
||||||
|
msr_shadow |= VKY3_A_1024x768;
|
||||||
|
a2560k_a_resolution.width = width;
|
||||||
|
a2560k_a_resolution.height = height;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_a2560k_a_set_sizes();
|
||||||
|
|
||||||
|
*VKY3_A_MCR = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Unsupported resolution */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the border of the screen (if supported)
|
||||||
|
*
|
||||||
|
* @param width the horizontal size of one side of the border (0 - 32 pixels)
|
||||||
|
* @param height the vertical size of one side of the border (0 - 32 pixels)
|
||||||
|
*/
|
||||||
|
void txt_a2560k_a_set_border(short width, short height) {
|
||||||
|
if ((width > 0) || (height > 0)) {
|
||||||
|
a2560k_a_border_width = width;
|
||||||
|
a2560k_a_border_height = height;
|
||||||
|
*VKY3_A_BCR = (height & 0x3f) << 16 | (width & 0x3f) << 8 | VKY3_A_BCR_ENABLE;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_a2560k_a_set_sizes();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
a2560k_a_border_width = 0;
|
||||||
|
a2560k_a_border_height = 0;
|
||||||
|
*VKY3_A_BCR = 0;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_a2560k_a_set_sizes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the border of the screen (if supported)
|
||||||
|
*
|
||||||
|
* @param red the red component of the color (0 - 255)
|
||||||
|
* @param green the green component of the color (0 - 255)
|
||||||
|
* @param blue the blue component of the color (0 - 255)
|
||||||
|
*/
|
||||||
|
void txt_a2560k_a_set_border_color(unsigned char red, unsigned char green, unsigned char blue) {
|
||||||
|
*VKY3_A_BRDCOLOR = (unsigned long)(((red & 0xff) << 16) | ((green & 0xff) << 8) | (blue & 0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a font as the current font for the screen
|
||||||
|
*
|
||||||
|
* @param width width of a character in pixels
|
||||||
|
* @param height of a character in pixels
|
||||||
|
* @param data pointer to the raw font data to be loaded
|
||||||
|
*/
|
||||||
|
short txt_a2560k_a_set_font(short width, short height, const unsigned char * data) {
|
||||||
|
if (((width == 8) && (height == 8)) || ((width == 8) && (height == 16))) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* The size is valid... set the font */
|
||||||
|
a2560k_a_font_size.width = width;
|
||||||
|
a2560k_a_font_size.height = height;
|
||||||
|
|
||||||
|
/* Set the size of the character and container */
|
||||||
|
*VKY3_A_FM0 = ((height & 0xff) << 24) | ((width & 0xff) << 16) | ((height & 0xff) << 8) | (width & 0xff);
|
||||||
|
|
||||||
|
/* Copy the font data... this assumes a width of one byte! */
|
||||||
|
/* TODO: generalize this for all possible font sizes */
|
||||||
|
for (i = 0; i < 256 * height; i++) {
|
||||||
|
VKY3_A_FONT_MEMORY[i] = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_a2560k_a_set_sizes();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the appearance of the cursor
|
||||||
|
*
|
||||||
|
* @param enable 0 to hide, any other number to make visible
|
||||||
|
* @param rate the blink rate for the cursor (0=1s, 1=0.5s, 2=0.25s, 3=1/5s)
|
||||||
|
* @param c the character in the current font to use as a cursor
|
||||||
|
*/
|
||||||
|
void txt_a2560k_a_set_cursor(short enable, short rate, char c) {
|
||||||
|
*VKY3_A_CCR = ((a2560k_a_color & 0xff) << 24) | ((c & 0xff) << 16) | ((rate & 0x03) << 1) | (enable & 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set if the cursor is visible or not
|
||||||
|
*
|
||||||
|
* @param enable 0 to hide, any other number to make visible
|
||||||
|
*/
|
||||||
|
void txt_a2560k_a_set_cursor_visible(short enable) {
|
||||||
|
if (enable) {
|
||||||
|
*VKY3_A_CCR |= 0x01;
|
||||||
|
} else {
|
||||||
|
*VKY3_A_CCR &= ~0x01;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the current region
|
||||||
|
*
|
||||||
|
* @param region pointer to a t_rect describing the rectangular region (using character cells for size and size)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the region was invalid
|
||||||
|
*/
|
||||||
|
short txt_a2560k_a_get_region(p_rect region) {
|
||||||
|
region->origin.x = a2560k_a_region.origin.x;
|
||||||
|
region->origin.y = a2560k_a_region.origin.y;
|
||||||
|
region->size.width = a2560k_a_region.size.width;
|
||||||
|
region->size.height = a2560k_a_region.size.height;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a region to restrict further character display, scrolling, etc.
|
||||||
|
* Note that a region of zero size will reset the region to the full size of the screen.
|
||||||
|
*
|
||||||
|
* @param region pointer to a t_rect describing the rectangular region (using character cells for size and size)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the region was invalid
|
||||||
|
*/
|
||||||
|
short txt_a2560k_a_set_region(p_rect region) {
|
||||||
|
if ((region->size.width == 0) || (region->size.height == 0)) {
|
||||||
|
/* Set the region to the default (full screen) */
|
||||||
|
a2560k_a_region.origin.x = 0;
|
||||||
|
a2560k_a_region.origin.y = 0;
|
||||||
|
a2560k_a_region.size.width = a2560k_a_visible_size.width;
|
||||||
|
a2560k_a_region.size.height = a2560k_a_visible_size.height;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
a2560k_a_region.origin.x = region->origin.x;
|
||||||
|
a2560k_a_region.origin.y = region->origin.y;
|
||||||
|
a2560k_a_region.size.width = region->size.width;
|
||||||
|
a2560k_a_region.size.height = region->size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default foreground and background colors for printing
|
||||||
|
*
|
||||||
|
* @param pointer to the foreground the Text LUT index of the new current foreground color (0 - 15)
|
||||||
|
* @param pointer to the background the Text LUT index of the new current background color (0 - 15)
|
||||||
|
*/
|
||||||
|
short txt_a2560k_a_get_color(unsigned char * foreground, unsigned char * background) {
|
||||||
|
*foreground = (a2560k_a_color & 0xf0) >> 4;
|
||||||
|
*background = a2560k_a_color & 0x0f;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default foreground and background colors for printing
|
||||||
|
*
|
||||||
|
* @param foreground the Text LUT index of the new current foreground color (0 - 15)
|
||||||
|
* @param background the Text LUT index of the new current background color (0 - 15)
|
||||||
|
*/
|
||||||
|
short txt_a2560k_a_set_color(unsigned char foreground, unsigned char background) {
|
||||||
|
a2560k_a_color = ((foreground & 0x0f) << 4) + (background & 0x0f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll the text in the current region
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param horizontal the number of columns to scroll (negative is left, positive is right)
|
||||||
|
* @param vertical the number of rows to scroll (negative is down, positive is up)
|
||||||
|
*/
|
||||||
|
void txt_a2560k_a_scroll(short horizontal, short vertical) {
|
||||||
|
short x, x0, x1, x2, x3, dx;
|
||||||
|
short y, y0, y1, y2, y3, dy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine limits of rectangles to move and fill and directions of loops
|
||||||
|
* x0 and y0 are the positions of the first cell to be over-written
|
||||||
|
* x1 and y1 are the positions of the first cell to be copyed... TEXT[x0,y0] := TEXT[x1,y1]
|
||||||
|
* x2 and y2 are the position of the last cell to be over-written
|
||||||
|
* x3 and y3 are the position of the last cell to be copied... TEXT[x2,y2] := TEXT[x3,y3]
|
||||||
|
*
|
||||||
|
* When blanking, the rectangles (x2,y0) - (x3,y3) and (x0,y2) - (x2,y3) are cleared
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Determine the row limits
|
||||||
|
|
||||||
|
if (vertical >= 0) {
|
||||||
|
y0 = a2560k_a_region.origin.y;
|
||||||
|
y1 = y0 + vertical;
|
||||||
|
y3 = a2560k_a_region.origin.y + a2560k_a_region.size.height;
|
||||||
|
y2 = y3 - vertical;
|
||||||
|
dy = 1;
|
||||||
|
} else {
|
||||||
|
y0 = a2560k_a_region.origin.y + a2560k_a_region.size.height - 1;
|
||||||
|
y1 = y0 + vertical;
|
||||||
|
y3 = a2560k_a_region.origin.y - 1;
|
||||||
|
y2 = y3 - vertical;
|
||||||
|
dy = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the column limits
|
||||||
|
|
||||||
|
if (horizontal >= 0) {
|
||||||
|
x0 = a2560k_a_region.origin.x;
|
||||||
|
x1 = x0 + horizontal;
|
||||||
|
x3 = a2560k_a_region.origin.x + a2560k_a_region.size.width;
|
||||||
|
x2 = x3 - horizontal;
|
||||||
|
dx = 1;
|
||||||
|
} else {
|
||||||
|
x0 = a2560k_a_region.origin.x + a2560k_a_region.size.width - 1;
|
||||||
|
x1 = x0 + horizontal;
|
||||||
|
x3 = a2560k_a_region.origin.x - 1;
|
||||||
|
x2 = x3 - horizontal;
|
||||||
|
dx = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the rectangle */
|
||||||
|
|
||||||
|
for (y = y0; y != y2; y += dy) {
|
||||||
|
int row_dst = y * a2560k_a_max_size.width;
|
||||||
|
int row_src = (y + vertical) * a2560k_a_max_size.width;
|
||||||
|
for (x = x0; x != x2; x += dx) {
|
||||||
|
int offset_dst = row_dst + x;
|
||||||
|
int offset_src = row_src + x + horizontal;
|
||||||
|
VKY3_A_TEXT_MATRIX[offset_dst] = VKY3_A_TEXT_MATRIX[offset_src];
|
||||||
|
VKY3_A_COLOR_MATRIX[offset_dst] = VKY3_A_COLOR_MATRIX[offset_src];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the rectangles */
|
||||||
|
|
||||||
|
if (horizontal != 0) {
|
||||||
|
for (y = y0; y != y3; y += dy) {
|
||||||
|
int row_dst = y * a2560k_a_max_size.width;
|
||||||
|
for (x = x2; x != x3; x += dx) {
|
||||||
|
VKY3_A_TEXT_MATRIX[row_dst + x] = ' ';
|
||||||
|
VKY3_A_COLOR_MATRIX[row_dst + x] = a2560k_a_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertical != 0) {
|
||||||
|
for (y = y2; y != y3; y += dy) {
|
||||||
|
int row_dst = y * a2560k_a_max_size.width;
|
||||||
|
for (x = x0; x != x3; x += dx) {
|
||||||
|
VKY3_A_TEXT_MATRIX[row_dst + x] = ' ';
|
||||||
|
VKY3_A_COLOR_MATRIX[row_dst + x] = a2560k_a_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the current region with a character in the current color
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param c the character to fill the region with
|
||||||
|
*/
|
||||||
|
void txt_a2560k_a_fill(char c) {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
for (y = 0; y < a2560k_a_region.size.height; y++) {
|
||||||
|
int offset_row = (a2560k_a_region.origin.y + y) * a2560k_a_max_size.width;
|
||||||
|
for (x = 0; x < a2560k_a_region.size.width; x++) {
|
||||||
|
int offset = offset_row + a2560k_a_region.origin.x + x;
|
||||||
|
VKY3_A_TEXT_MATRIX[offset] = c;
|
||||||
|
VKY3_A_COLOR_MATRIX[offset] = a2560k_a_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the position of the cursor to (x, y) relative to the current region
|
||||||
|
* If the (x, y) coordinate is outside the region, it will be clipped to the region.
|
||||||
|
* If y is greater than the height of the region, the region will scroll until that relative
|
||||||
|
* position would be within view.
|
||||||
|
*
|
||||||
|
* @param x the column for the cursor
|
||||||
|
* @param y the row for the cursor
|
||||||
|
*/
|
||||||
|
void txt_a2560k_a_set_xy(short x, short y) {
|
||||||
|
/* Make sure X is within range for the current region... "print" a newline if not */
|
||||||
|
if (x < 0) {
|
||||||
|
x = 0;
|
||||||
|
} else if (x >= a2560k_a_region.size.width) {
|
||||||
|
x = 0;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure Y is within range for the current region... scroll if not */
|
||||||
|
if (y < 0) {
|
||||||
|
y = 0;
|
||||||
|
} else if (y >= a2560k_a_region.size.height) {
|
||||||
|
txt_a2560k_a_scroll(0, y - a2560k_a_region.size.height + 1);
|
||||||
|
y = a2560k_a_region.size.height - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
a2560k_a_cursor.x = x;
|
||||||
|
a2560k_a_cursor.y = y;
|
||||||
|
|
||||||
|
/* Set register */
|
||||||
|
*VKY3_A_CPR = (((a2560k_a_region.origin.y + y) & 0xffff) << 16) | ((a2560k_a_region.origin.x + x) & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position of the cursor (x, y) relative to the current region
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param position pointer to a t_point record to fill out
|
||||||
|
*/
|
||||||
|
void txt_a2560k_a_get_xy(p_point position) {
|
||||||
|
position->x = a2560k_a_cursor.x;
|
||||||
|
position->y = a2560k_a_cursor.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a character to the current cursor position in the current color
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param c the character to print
|
||||||
|
*/
|
||||||
|
void txt_a2560k_a_put(char c) {
|
||||||
|
short x;
|
||||||
|
short y;
|
||||||
|
unsigned int offset;
|
||||||
|
|
||||||
|
x = a2560k_a_region.origin.x + a2560k_a_cursor.x;
|
||||||
|
y = a2560k_a_region.origin.y + a2560k_a_cursor.y;
|
||||||
|
offset = y * a2560k_a_max_size.width + x;
|
||||||
|
VKY3_A_TEXT_MATRIX[offset] = c;
|
||||||
|
VKY3_A_COLOR_MATRIX[offset] = a2560k_a_color;
|
||||||
|
|
||||||
|
txt_a2560k_a_set_xy(a2560k_a_cursor.x + 1, a2560k_a_cursor.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the screen
|
||||||
|
*/
|
||||||
|
void txt_a2560k_a_init() {
|
||||||
|
char buffer[255];
|
||||||
|
t_rect region;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Kick the PLL
|
||||||
|
// If VICKY is generating a 40MHz signal, we need to switch the bit to go to 40MHz before
|
||||||
|
// clearing it to go back to 25MHz.
|
||||||
|
if (*VKY3_A_MCR & VKY3_A_CLK40) {
|
||||||
|
*VKY3_A_MCR |= VKY3_A_1024x768;
|
||||||
|
*VKY3_A_MCR &= ~(VKY3_A_1024x768);
|
||||||
|
}
|
||||||
|
|
||||||
|
a2560k_a_resolution.width = 0;
|
||||||
|
a2560k_a_resolution.height = 0;
|
||||||
|
a2560k_a_font_size.width = 0;
|
||||||
|
a2560k_a_font_size.height = 0;
|
||||||
|
|
||||||
|
/* Disable the set_sizes call for now */
|
||||||
|
a2560k_a_enable_set_sizes = 0;
|
||||||
|
|
||||||
|
/* Start with nothing on */
|
||||||
|
msr_shadow = 0;
|
||||||
|
|
||||||
|
/* Define the capabilities */
|
||||||
|
|
||||||
|
/* Specify the screen number */
|
||||||
|
a2560k_a_caps.number = TXT_SCREEN_A2560K_A;
|
||||||
|
|
||||||
|
/* This screen can be text or can be put to sleep */
|
||||||
|
a2560k_a_caps.supported_modes = TXT_MODE_TEXT | TXT_MODE_SLEEP;
|
||||||
|
|
||||||
|
/* Resolutions supported: 800x600, 1024x768 */
|
||||||
|
a2560k_a_resolutions[0].width = 800;
|
||||||
|
a2560k_a_resolutions[0].height = 600;
|
||||||
|
a2560k_a_resolutions[1].width = 1024;
|
||||||
|
a2560k_a_resolutions[1].height = 768;
|
||||||
|
a2560k_a_caps.resolution_count = 2;
|
||||||
|
a2560k_a_caps.resolutions = a2560k_a_resolutions;
|
||||||
|
|
||||||
|
/* At the moment, support only 8x8 and 8x16 fonts */
|
||||||
|
/* TODO: add support for all possible font sizes */
|
||||||
|
a2560k_a_fonts[0].width = 8;
|
||||||
|
a2560k_a_fonts[0].height = 8;
|
||||||
|
a2560k_a_fonts[1].width = 8;
|
||||||
|
a2560k_a_fonts[1].height = 16;
|
||||||
|
a2560k_a_caps.font_size_count = 2;
|
||||||
|
a2560k_a_caps.font_sizes = a2560k_a_fonts;
|
||||||
|
|
||||||
|
/* Initialze the color lookup tables */
|
||||||
|
for (i = 0; i < VKY3_A_LUT_SIZE; i++) {
|
||||||
|
VKY3_A_TEXT_LUT_FG[i] = a2560k_a_lut[i];
|
||||||
|
VKY3_A_TEXT_LUT_BG[i] = a2560k_a_lut[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the mode to text */
|
||||||
|
txt_a2560k_a_set_mode(TXT_MODE_TEXT);
|
||||||
|
|
||||||
|
/* Set the resolution */
|
||||||
|
txt_a2560k_a_set_resolution(800, 600); /* Default resolution is 800x600 */
|
||||||
|
|
||||||
|
/* Set the default color: light grey on blue */
|
||||||
|
#if MODEL_FOENIX_A2560X
|
||||||
|
txt_a2560k_a_set_color(0x0F, 0x08);
|
||||||
|
#else
|
||||||
|
txt_a2560k_a_set_color(0x07, 0x04);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Set the font */
|
||||||
|
txt_a2560k_a_set_font(8, 8, MSX_CP437_8x8_bin); /* Use 8x8 font */
|
||||||
|
|
||||||
|
/* Set the cursor */
|
||||||
|
txt_a2560k_a_set_cursor(1, 0, 0xB1);
|
||||||
|
|
||||||
|
/* Set the border */
|
||||||
|
#if MODEL_FOENIX_A2560X
|
||||||
|
txt_a2560k_a_set_border(8, 8); /* Set up the border */
|
||||||
|
txt_a2560k_a_set_border_color(0x10, 0x00, 0x10);
|
||||||
|
#else
|
||||||
|
txt_a2560k_a_set_border(16, 16); /* Set up the border */
|
||||||
|
txt_a2560k_a_set_border_color(0, 0, 0x3f);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable set_sizes, now that everything is set up initially
|
||||||
|
* And calculate the size of the screen
|
||||||
|
*/
|
||||||
|
a2560k_a_enable_set_sizes = 1;
|
||||||
|
txt_a2560k_a_set_sizes();
|
||||||
|
|
||||||
|
/* Set region to default */
|
||||||
|
region.origin.x = 0;
|
||||||
|
region.origin.y = 0;
|
||||||
|
region.size.width = 0;
|
||||||
|
region.size.height = 0;
|
||||||
|
txt_a2560k_a_set_region(®ion);
|
||||||
|
|
||||||
|
/* Home the cursor */
|
||||||
|
txt_a2560k_a_set_xy(0, 0);
|
||||||
|
|
||||||
|
/* Clear the screen */
|
||||||
|
txt_a2560k_a_fill(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize and install the driver
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
short txt_a2560k_a_install() {
|
||||||
|
t_txt_device device;
|
||||||
|
|
||||||
|
device.number = TXT_SCREEN_A2560K_A;
|
||||||
|
device.name = "SCREEN A";
|
||||||
|
|
||||||
|
device.init = txt_a2560k_a_init;
|
||||||
|
device.get_capabilities = txt_a2560k_a_get_capabilities;
|
||||||
|
device.set_mode = txt_a2560k_a_set_mode;
|
||||||
|
device.set_sizes = txt_a2560k_a_set_sizes;
|
||||||
|
device.set_resolution = txt_a2560k_a_set_resolution;
|
||||||
|
device.set_border = txt_a2560k_a_set_border;
|
||||||
|
device.set_border_color = txt_a2560k_a_set_border_color;
|
||||||
|
device.set_font = txt_a2560k_a_set_font;
|
||||||
|
device.set_cursor = txt_a2560k_a_set_cursor;
|
||||||
|
device.set_cursor_visible = txt_a2560k_a_set_cursor_visible;
|
||||||
|
device.get_region = txt_a2560k_a_get_region;
|
||||||
|
device.set_region = txt_a2560k_a_set_region;
|
||||||
|
device.get_color = txt_a2560k_a_get_color;
|
||||||
|
device.set_color = txt_a2560k_a_set_color;
|
||||||
|
device.set_xy = txt_a2560k_a_set_xy;
|
||||||
|
device.get_xy = txt_a2560k_a_get_xy;
|
||||||
|
device.put = txt_a2560k_a_put;
|
||||||
|
device.scroll = txt_a2560k_a_scroll;
|
||||||
|
device.fill = txt_a2560k_a_fill;
|
||||||
|
device.get_sizes = txt_a2560k_a_get_sizes;
|
||||||
|
|
||||||
|
return txt_register(&device);
|
||||||
|
}
|
21
src/dev/txt_a2560k_a.h
Normal file
21
src/dev/txt_a2560k_a.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/** @file txt_a2560k_a.h
|
||||||
|
*
|
||||||
|
* Text screen driver for A2560K Channel A
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TXT_A2560K_A_H
|
||||||
|
#define __TXT_A2560K_A_H
|
||||||
|
|
||||||
|
/* Channel A is assigned to screen #1, it will be considered a secondary channel */
|
||||||
|
#define TXT_SCREEN_A2560K_A 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize and install the driver
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
extern short txt_a2560k_a_install();
|
||||||
|
|
||||||
|
extern t_extent a2560k_a_max_size;
|
||||||
|
|
||||||
|
#endif
|
717
src/dev/txt_a2560k_b.c
Normal file
717
src/dev/txt_a2560k_b.c
Normal file
|
@ -0,0 +1,717 @@
|
||||||
|
/** @file txt_a2560k_B.c
|
||||||
|
*
|
||||||
|
* Text screen driver for A2560K Channel B
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "log.h"
|
||||||
|
#include "sys_general.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
#include "A2560K/vky_chan_a.h"
|
||||||
|
#include "A2560K/vky_chan_b.h"
|
||||||
|
#include "dev/txt_screen.h"
|
||||||
|
#include "dev/txt_a2560k_b.h"
|
||||||
|
|
||||||
|
extern const unsigned char MSX_CP437_8x8_bin[];
|
||||||
|
|
||||||
|
/* Default text color lookup table values (AARRGGBB) */
|
||||||
|
const unsigned long a2560k_b_lut[VKY3_B_LUT_SIZE] = {
|
||||||
|
0xFF000000, // Black (transparent) - 0x00
|
||||||
|
0xFF800000, // Mid-Tone Red - 0x01
|
||||||
|
0xFF008000, // Mid-Tone Green - 0x02
|
||||||
|
0xFF808000, // Mid-Tone Yellow - 0x03
|
||||||
|
0xFF000080, // Mid-Tone Blue - 0x04
|
||||||
|
0xFFAA5500, // Mid-Tone Orange - 0x05
|
||||||
|
0xFF008080, // Mid-Tone Cian - 0x06
|
||||||
|
0xFF808080, // 50% Grey - 0x07
|
||||||
|
#if MODEL_FOENIX_A2560X
|
||||||
|
0xFF202020, // Dark Grey
|
||||||
|
#else
|
||||||
|
0xFF555555, // Dark Grey
|
||||||
|
#endif
|
||||||
|
0xFFFF0000, // Bright Red - 0x09
|
||||||
|
0xFF55FF55, // Bright Green - 0x0A
|
||||||
|
0xFFFFFF55, // Bright Yellow - 0x0B
|
||||||
|
0xFF5555FF, // Bright Blue - 0x0C
|
||||||
|
0xFFFF7FFF, // Bright Orange - 0x0D
|
||||||
|
0xFF55FFFF, // Bright Cyan - 0x0E
|
||||||
|
0xFFFFFFFF // White - 0x0F
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver level variables for the screen
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned char a2560k_b_enable_set_sizes; /* Flag to enable set_sizes to actually do its computation */
|
||||||
|
t_txt_capabilities a2560k_b_caps; /* The capabilities of Channel B */
|
||||||
|
t_extent a2560k_b_resolutions[6]; /* The list of display resolutions */
|
||||||
|
t_extent a2560k_b_fonts[1]; /* The list of font resolutions */
|
||||||
|
t_rect a2560k_b_region; /* The current region */
|
||||||
|
t_point a2560k_b_cursor; /* The current cursor position */
|
||||||
|
t_extent a2560k_b_resolution; /* The current display resolution */
|
||||||
|
t_extent a2560k_b_font_size; /* The current font size */
|
||||||
|
t_extent a2560k_b_max_size; /* The size of the screen in characters (without border removed) */
|
||||||
|
t_extent a2560k_b_visible_size; /* The size of the visible screen in characters (with border removed) */
|
||||||
|
short a2560k_b_border_width; /* Width of the border on one side */
|
||||||
|
short a2560k_b_border_height; /* Height of the border on one side */
|
||||||
|
unsigned char a2560k_b_color; /* The current color */
|
||||||
|
unsigned long msr_shadow_b; /* A shadow register for the Master Control Register */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the description of a screen's capabilities
|
||||||
|
*
|
||||||
|
* @return a pointer to the read-only description (0 on error)
|
||||||
|
*/
|
||||||
|
const p_txt_capabilities txt_a2560k_b_get_capabilities() {
|
||||||
|
return &a2560k_b_caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the size of the text screen in rows and columns so that
|
||||||
|
* the kernel printing routines can work correctly.
|
||||||
|
*
|
||||||
|
* NOTE: this should be called whenever the VKY3 Channel B registers are changed
|
||||||
|
*/
|
||||||
|
void txt_a2560k_b_set_sizes() {
|
||||||
|
if (a2560k_b_enable_set_sizes) {
|
||||||
|
/* Only recalculate after initialization is mostly completed */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the maximum number of characters visible on the screen
|
||||||
|
* This controls text layout in memory
|
||||||
|
*/
|
||||||
|
a2560k_b_max_size.width = a2560k_b_resolution.width / a2560k_b_font_size.width;
|
||||||
|
a2560k_b_max_size.height = a2560k_b_resolution.height / a2560k_b_font_size.height;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the characters that are visible in whole or in part
|
||||||
|
*/
|
||||||
|
short border_width = (2 * a2560k_b_border_width) / a2560k_b_font_size.width;
|
||||||
|
short border_height = (2 * a2560k_b_border_height) / a2560k_b_font_size.height;
|
||||||
|
a2560k_b_visible_size.width = a2560k_b_max_size.width - border_width;
|
||||||
|
a2560k_b_visible_size.height = a2560k_b_max_size.height - border_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the display resolutions
|
||||||
|
*
|
||||||
|
* @param text_size the size of the screen in visible characters (may be null)
|
||||||
|
* @param pixel_size the size of the screen in pixels (may be null)
|
||||||
|
*/
|
||||||
|
void txt_a2560k_b_get_sizes(p_extent text_size, p_extent pixel_size) {
|
||||||
|
if (text_size) {
|
||||||
|
text_size->width = a2560k_b_visible_size.width;
|
||||||
|
text_size->height = a2560k_b_visible_size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixel_size) {
|
||||||
|
pixel_size->width = a2560k_b_resolution.width;
|
||||||
|
pixel_size->height = a2560k_b_resolution.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the display mode for the screen
|
||||||
|
*
|
||||||
|
* @param mode a bitfield of desired display mode options
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the mode is invalid for the screen
|
||||||
|
*/
|
||||||
|
short txt_a2560k_b_set_mode(short mode) {
|
||||||
|
/* Turn off anything not set */
|
||||||
|
msr_shadow_b &= ~(VKY3_B_MCR_TEXT | VKY3_B_MCR_TXT_OVR | VKY3_B_MCR_GRAPHICS | VKY3_B_MCR_BITMAP | VKY3_B_MCR_TILE | VKY3_B_MCR_SPRITE);
|
||||||
|
|
||||||
|
if (mode & TXT_MODE_SLEEP) {
|
||||||
|
/* Put the monitor to sleep: overrides all other option bits */
|
||||||
|
msr_shadow_b |= VKY3_B_MCR_SLEEP;
|
||||||
|
*VKY3_B_MCR = msr_shadow_b;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (mode & ~(TXT_MODE_TEXT | TXT_MODE_BITMAP | TXT_MODE_SPRITE | TXT_MODE_TILE)) {
|
||||||
|
/* A mode bit was set beside one of the supported ones... */
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (mode & TXT_MODE_TEXT) {
|
||||||
|
msr_shadow_b |= VKY3_B_MCR_TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode & TXT_MODE_BITMAP) {
|
||||||
|
msr_shadow_b |= VKY3_B_MCR_GRAPHICS | VKY3_B_MCR_BITMAP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode & TXT_MODE_SPRITE) {
|
||||||
|
msr_shadow_b |= VKY3_B_MCR_GRAPHICS | VKY3_B_MCR_SPRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode & TXT_MODE_TILE) {
|
||||||
|
msr_shadow_b |= VKY3_B_MCR_GRAPHICS | VKY3_B_MCR_TILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((msr_shadow_b & (VKY3_B_MCR_GRAPHICS | VKY3_B_MCR_TEXT)) == (VKY3_B_MCR_GRAPHICS | VKY3_B_MCR_TEXT)) {
|
||||||
|
msr_shadow_b |= VKY3_B_MCR_TXT_OVR;
|
||||||
|
}
|
||||||
|
|
||||||
|
*VKY3_B_MCR = msr_shadow_b;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the display resolution of the screen
|
||||||
|
*
|
||||||
|
* @param width the desired horizontal resolution in pixels
|
||||||
|
* @param height the desired veritical resolution in pixels
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the resolution is unsupported
|
||||||
|
*/
|
||||||
|
short txt_a2560k_b_set_resolution(short width, short height) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// If no size specified, set it based on the DIP switch
|
||||||
|
if ((width == 0) || (height == 0)) {
|
||||||
|
if ((*VKY3_B_MCR & VKY3_B_HIRES) == 0) {
|
||||||
|
width = 800;
|
||||||
|
height = 600;
|
||||||
|
} else {
|
||||||
|
width = 640;
|
||||||
|
height = 480;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kick the PLL
|
||||||
|
// If VICKY is generating a 40MHz signal, we need to switch the bit to go to 40MHz before
|
||||||
|
// clearing it to go back to 25MHz.
|
||||||
|
if (*VKY3_B_MCR & VKY3_B_CLK40) {
|
||||||
|
*VKY3_B_MCR |= VKY3_B_PLL | VKY3_B_MODE1;
|
||||||
|
*VKY3_B_MCR &= ~(VKY3_B_PLL | VKY3_B_MODE1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < a2560k_b_caps.resolution_count; i++) {
|
||||||
|
if ((a2560k_b_caps.resolutions[i].width == width) && (a2560k_b_caps.resolutions[i].height == height)) {
|
||||||
|
msr_shadow_b &= ~(VKY3_B_DOUBLE | VKY3_B_MODE0 | VKY3_B_MODE1);
|
||||||
|
if (height < 400) {
|
||||||
|
/* We're in pixel doubling range */
|
||||||
|
msr_shadow_b |= VKY3_B_DOUBLE;
|
||||||
|
|
||||||
|
/* Figure out what the base resolution is */
|
||||||
|
height *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the height to determine the resolution we should set
|
||||||
|
switch (height) {
|
||||||
|
case 400: // 640x400 or 320x200 (mode = 11)
|
||||||
|
msr_shadow_b |= VKY3_B_MODE0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 480: // 640x480 or 320x240 (mode = 00)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 600: // 800x600 or 400x300 (mode = 01)
|
||||||
|
msr_shadow_b |= VKY3_B_PLL | VKY3_B_MODE1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Shouldn't get here... bad resolution
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the kernel variables
|
||||||
|
a2560k_b_resolution.width = width;
|
||||||
|
a2560k_b_resolution.height = height;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_a2560k_b_set_sizes();
|
||||||
|
|
||||||
|
// Kick the PLL
|
||||||
|
if (*VKY3_B_MCR & VKY3_B_PLL) {
|
||||||
|
*VKY3_B_MCR &= ~(VKY3_B_PLL | VKY3_B_MODE0 | VKY3_B_MODE1);
|
||||||
|
*VKY3_B_MCR |= (VKY3_B_PLL | VKY3_B_MODE1);
|
||||||
|
}
|
||||||
|
*VKY3_B_MCR &= ~(VKY3_B_PLL | VKY3_B_MODE0 | VKY3_B_MODE1);
|
||||||
|
|
||||||
|
// Update the register
|
||||||
|
*VKY3_B_MCR = msr_shadow_b;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the border of the screen (if supported)
|
||||||
|
*
|
||||||
|
* @param width the horizontal size of one side of the border (0 - 32 pixels)
|
||||||
|
* @param height the vertical size of one side of the border (0 - 32 pixels)
|
||||||
|
*/
|
||||||
|
void txt_a2560k_b_set_border(short width, short height) {
|
||||||
|
if ((width > 0) || (height > 0)) {
|
||||||
|
a2560k_b_border_width = width;
|
||||||
|
a2560k_b_border_height = height;
|
||||||
|
*VKY3_B_BCR = (height & 0x3f) << 16 | (width & 0x3f) << 8 | VKY3_B_BCR_ENABLE;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_a2560k_b_set_sizes();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
a2560k_b_border_width = 0;
|
||||||
|
a2560k_b_border_height = 0;
|
||||||
|
*VKY3_B_BCR = 0;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_a2560k_b_set_sizes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the border of the screen (if supported)
|
||||||
|
*
|
||||||
|
* @param red the red component of the color (0 - 255)
|
||||||
|
* @param green the green component of the color (0 - 255)
|
||||||
|
* @param blue the blue component of the color (0 - 255)
|
||||||
|
*/
|
||||||
|
void txt_a2560k_b_set_border_color(unsigned char red, unsigned char green, unsigned char blue) {
|
||||||
|
*VKY3_B_BRDCOLOR = (unsigned long)(((red & 0xff) << 16) | ((green & 0xff) << 8) | (blue & 0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a font as the current font for the screen
|
||||||
|
*
|
||||||
|
* @param width width of a character in pixels
|
||||||
|
* @param height of a character in pixels
|
||||||
|
* @param data pointer to the raw font data to be loaded
|
||||||
|
*/
|
||||||
|
short txt_a2560k_b_set_font(short width, short height, const unsigned char * data) {
|
||||||
|
if ((width == 8) && (height == 8)) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* The size is valid... set the font */
|
||||||
|
a2560k_b_font_size.width = width;
|
||||||
|
a2560k_b_font_size.height = height;
|
||||||
|
|
||||||
|
/* Copy the font data... this assumes a width of one byte! */
|
||||||
|
for (i = 0; i < 256 * height; i++) {
|
||||||
|
VKY3_B_FONT_MEMORY[i] = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the appearance of the cursor
|
||||||
|
*
|
||||||
|
* @param enable 0 to hide, any other number to make visible
|
||||||
|
* @param rate the blink rate for the cursor (0=1s, 1=0.5s, 2=0.25s, 3=1/5s)
|
||||||
|
* @param c the character in the current font to use as a cursor
|
||||||
|
*/
|
||||||
|
void txt_a2560k_b_set_cursor(short enable, short rate, char c) {
|
||||||
|
*VKY3_B_CCR = ((a2560k_b_color & 0xff) << 24) | ((c & 0xff) << 16) | ((rate & 0x03) << 1) | (enable & 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set if the cursor is visible or not
|
||||||
|
*
|
||||||
|
* @param enable 0 to hide, any other number to make visible
|
||||||
|
*/
|
||||||
|
void txt_a2560k_b_set_cursor_visible(short enable) {
|
||||||
|
if (enable) {
|
||||||
|
*VKY3_B_CCR |= 0x01;
|
||||||
|
} else {
|
||||||
|
*VKY3_B_CCR &= ~0x01;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a region to restrict further character display, scrolling, etc.
|
||||||
|
* Note that a null region pointer and a region of zero size will reset the region to the full size of the screen.
|
||||||
|
*
|
||||||
|
* @param region pointer to a t_rect describing the rectangular region (using character cells for size and size)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the region was invalid
|
||||||
|
*/
|
||||||
|
short txt_a2560k_b_set_region(p_rect region) {
|
||||||
|
if ((region->size.width == 0) || (region->size.height == 0)) {
|
||||||
|
/* Set the region to the default (full screen) */
|
||||||
|
a2560k_b_region.origin.x = 0;
|
||||||
|
a2560k_b_region.origin.y = 0;
|
||||||
|
a2560k_b_region.size.width = a2560k_b_visible_size.width;
|
||||||
|
a2560k_b_region.size.height = a2560k_b_visible_size.height;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
a2560k_b_region.origin.x = region->origin.x;
|
||||||
|
a2560k_b_region.origin.y = region->origin.y;
|
||||||
|
a2560k_b_region.size.width = region->size.width;
|
||||||
|
a2560k_b_region.size.height = region->size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the current region
|
||||||
|
*
|
||||||
|
* @param region pointer to a t_rect describing the rectangular region (using character cells for size and size)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the region was invalid
|
||||||
|
*/
|
||||||
|
short txt_a2560k_b_get_region(p_rect region) {
|
||||||
|
region->origin.x = a2560k_b_region.origin.x;
|
||||||
|
region->origin.y = a2560k_b_region.origin.y;
|
||||||
|
region->size.width = a2560k_b_region.size.width;
|
||||||
|
region->size.height = a2560k_b_region.size.height;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default foreground and background colors for printing
|
||||||
|
*
|
||||||
|
* @param foreground the Text LUT index of the new current foreground color (0 - 15)
|
||||||
|
* @param background the Text LUT index of the new current background color (0 - 15)
|
||||||
|
*/
|
||||||
|
short txt_a2560k_b_set_color(unsigned char foreground, unsigned char background) {
|
||||||
|
a2560k_b_color = ((foreground & 0x0f) << 4) | (background & 0x0f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default foreground and background colors for printing
|
||||||
|
*
|
||||||
|
* @param pointer to the foreground the Text LUT index of the new current foreground color (0 - 15)
|
||||||
|
* @param pointer to the background the Text LUT index of the new current background color (0 - 15)
|
||||||
|
*/
|
||||||
|
short txt_a2560k_b_get_color(unsigned char * foreground, unsigned char * background) {
|
||||||
|
*foreground = (a2560k_b_color & 0xf0) >> 4;
|
||||||
|
*background = a2560k_b_color & 0x0f;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll the text in the current region
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param horizontal the number of columns to scroll (negative is left, positive is right)
|
||||||
|
* @param vertical the number of rows to scroll (negative is down, positive is up)
|
||||||
|
*/
|
||||||
|
void txt_a2560k_b_scroll(short horizontal, short vertical) {
|
||||||
|
short x, x0, x1, x2, x3, dx;
|
||||||
|
short y, y0, y1, y2, y3, dy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine limits of rectangles to move and fill and directions of loops
|
||||||
|
* x0 and y0 are the positions of the first cell to be over-written
|
||||||
|
* x1 and y1 are the positions of the first cell to be copyed... TEXT[x0,y0] := TEXT[x1,y1]
|
||||||
|
* x2 and y2 are the position of the last cell to be over-written
|
||||||
|
* x3 and y3 are the position of the last cell to be copied... TEXT[x2,y2] := TEXT[x3,y3]
|
||||||
|
*
|
||||||
|
* When blanking, the rectangles (x2,y0) - (x3,y3) and (x0,y2) - (x2,y3) are cleared
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Determine the row limits
|
||||||
|
|
||||||
|
if (vertical >= 0) {
|
||||||
|
y0 = a2560k_b_region.origin.y;
|
||||||
|
y1 = y0 + vertical;
|
||||||
|
y3 = a2560k_b_region.origin.y + a2560k_b_region.size.height;
|
||||||
|
y2 = y3 - vertical;
|
||||||
|
dy = 1;
|
||||||
|
} else {
|
||||||
|
y0 = a2560k_b_region.origin.y + a2560k_b_region.size.height - 1;
|
||||||
|
y1 = y0 + vertical;
|
||||||
|
y3 = a2560k_b_region.origin.y - 1;
|
||||||
|
y2 = y3 - vertical;
|
||||||
|
dy = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the column limits
|
||||||
|
|
||||||
|
if (horizontal >= 0) {
|
||||||
|
x0 = a2560k_b_region.origin.x;
|
||||||
|
x1 = x0 + horizontal;
|
||||||
|
x3 = a2560k_b_region.origin.x + a2560k_b_region.size.width;
|
||||||
|
x2 = x3 - horizontal;
|
||||||
|
dx = 1;
|
||||||
|
} else {
|
||||||
|
x0 = a2560k_b_region.origin.x + a2560k_b_region.size.width - 1;
|
||||||
|
x1 = x0 + horizontal;
|
||||||
|
x3 = a2560k_b_region.origin.x - 1;
|
||||||
|
x2 = x3 - horizontal;
|
||||||
|
dx = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the rectangle */
|
||||||
|
|
||||||
|
for (y = y0; y != y2; y += dy) {
|
||||||
|
int row_dst = y * a2560k_b_max_size.width;
|
||||||
|
int row_src = (y + vertical) * a2560k_b_max_size.width;
|
||||||
|
|
||||||
|
for (x = x0; x != x2; x += dx) {
|
||||||
|
int offset_dst = row_dst + x;
|
||||||
|
int offset_src = row_src + x + horizontal;
|
||||||
|
|
||||||
|
VKY3_B_TEXT_MATRIX[offset_dst] = VKY3_B_TEXT_MATRIX[offset_src];
|
||||||
|
VKY3_B_COLOR_MATRIX[offset_dst] = VKY3_B_COLOR_MATRIX[offset_src];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the rectangles */
|
||||||
|
|
||||||
|
if (horizontal != 0) {
|
||||||
|
for (y = y0; y != y3; y += dy) {
|
||||||
|
int row_dst = y * a2560k_b_max_size.width;
|
||||||
|
for (x = x2; x != x3; x += dx) {
|
||||||
|
VKY3_B_TEXT_MATRIX[row_dst + x] = ' ';
|
||||||
|
VKY3_B_COLOR_MATRIX[row_dst + x] = a2560k_b_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertical != 0) {
|
||||||
|
for (y = y2; y != y3; y += dy) {
|
||||||
|
int row_dst = y * a2560k_b_max_size.width;
|
||||||
|
for (x = x0; x != x3; x += dx) {
|
||||||
|
VKY3_B_TEXT_MATRIX[row_dst + x] = ' ';
|
||||||
|
VKY3_B_COLOR_MATRIX[row_dst + x] = a2560k_b_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the current region with a character in the current color
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param c the character to fill the region with
|
||||||
|
*/
|
||||||
|
void txt_a2560k_b_fill(char c) {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
for (y = 0; y < a2560k_b_region.size.height; y++) {
|
||||||
|
int offset_row = (a2560k_b_region.origin.y + y) * a2560k_b_max_size.width;
|
||||||
|
for (x = 0; x < a2560k_b_region.size.width; x++) {
|
||||||
|
int offset = offset_row + a2560k_b_region.origin.x + x;
|
||||||
|
VKY3_B_TEXT_MATRIX[offset] = c;
|
||||||
|
VKY3_B_COLOR_MATRIX[offset] = a2560k_b_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the position of the cursor to (x, y) relative to the current region
|
||||||
|
* If the (x, y) coordinate is outside the region, it will be clipped to the region.
|
||||||
|
* If y is greater than the height of the region, the region will scroll until that relative
|
||||||
|
* position would be within view.
|
||||||
|
*
|
||||||
|
* @param x the column for the cursor
|
||||||
|
* @param y the row for the cursor
|
||||||
|
*/
|
||||||
|
void txt_a2560k_b_set_xy(short x, short y) {
|
||||||
|
/* Make sure X is within range for the current region... "print" a newline if not */
|
||||||
|
if (x < 0) {
|
||||||
|
x = 0;
|
||||||
|
} else if (x >= a2560k_b_region.size.width) {
|
||||||
|
x = 0;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure Y is within range for the current region... scroll if not */
|
||||||
|
if (y < 0) {
|
||||||
|
y = 0;
|
||||||
|
} else if (y >= a2560k_b_region.size.height) {
|
||||||
|
txt_a2560k_b_scroll(0, y - a2560k_b_region.size.height + 1);
|
||||||
|
y = a2560k_b_region.size.height - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
a2560k_b_cursor.x = x;
|
||||||
|
a2560k_b_cursor.y = y;
|
||||||
|
|
||||||
|
/* Set register */
|
||||||
|
*VKY3_B_CPR = (((a2560k_b_region.origin.y + y) & 0xffff) << 16) | ((a2560k_b_region.origin.x + x) & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position of the cursor (x, y) relative to the current region
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param position pointer to a t_point record to fill out
|
||||||
|
*/
|
||||||
|
void txt_a2560k_b_get_xy(p_point position) {
|
||||||
|
position->x = a2560k_b_cursor.x;
|
||||||
|
position->y = a2560k_b_cursor.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a character to the current cursor position in the current color
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param c the character to print
|
||||||
|
*/
|
||||||
|
void txt_a2560k_b_put(char c) {
|
||||||
|
short x;
|
||||||
|
short y;
|
||||||
|
unsigned int offset;
|
||||||
|
|
||||||
|
x = a2560k_b_region.origin.x + a2560k_b_cursor.x;
|
||||||
|
y = a2560k_b_region.origin.y + a2560k_b_cursor.y;
|
||||||
|
offset = y * a2560k_b_max_size.width + x;
|
||||||
|
VKY3_B_TEXT_MATRIX[offset] = c;
|
||||||
|
VKY3_B_COLOR_MATRIX[offset] = a2560k_b_color;
|
||||||
|
|
||||||
|
txt_a2560k_b_set_xy(a2560k_b_cursor.x + 1, a2560k_b_cursor.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the screen
|
||||||
|
*/
|
||||||
|
void txt_a2560k_b_init() {
|
||||||
|
char buffer[255];
|
||||||
|
t_rect region;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Kick the PLL
|
||||||
|
// If VICKY is generating a 40MHz signal, we need to switch the bit to go to 40MHz before
|
||||||
|
// clearing it to go back to 25MHz.
|
||||||
|
if (*VKY3_B_MCR & VKY3_B_CLK40) {
|
||||||
|
*VKY3_B_MCR |= VKY3_B_PLL | VKY3_B_MODE1;
|
||||||
|
*VKY3_B_MCR &= ~(VKY3_B_PLL | VKY3_B_MODE1);
|
||||||
|
}
|
||||||
|
|
||||||
|
a2560k_b_resolution.width = 0;
|
||||||
|
a2560k_b_resolution.height = 0;
|
||||||
|
a2560k_b_font_size.width = 0;
|
||||||
|
a2560k_b_font_size.height = 0;
|
||||||
|
|
||||||
|
/* Disable the set_sizes call for now */
|
||||||
|
a2560k_b_enable_set_sizes = 0;
|
||||||
|
|
||||||
|
/* Start with nothing on */
|
||||||
|
msr_shadow_b = 0;
|
||||||
|
|
||||||
|
/* Define the capabilities */
|
||||||
|
|
||||||
|
/* Specify the screen number */
|
||||||
|
a2560k_b_caps.number = TXT_SCREEN_A2560K_B;
|
||||||
|
|
||||||
|
/* This screen can be nothing, sleep, or any combination of text, sprite, bitmap, and tile */
|
||||||
|
a2560k_b_caps.supported_modes = TXT_MODE_TEXT | TXT_MODE_SPRITE | TXT_MODE_BITMAP | TXT_MODE_TILE | TXT_MODE_SLEEP;
|
||||||
|
|
||||||
|
/* Resolutions supported: 320x200, 320x240, 400x300, 640x400, 640x480, 800x600 */
|
||||||
|
a2560k_b_resolutions[0].width = 320;
|
||||||
|
a2560k_b_resolutions[0].height = 200;
|
||||||
|
a2560k_b_resolutions[1].width = 320;
|
||||||
|
a2560k_b_resolutions[1].height = 240;
|
||||||
|
a2560k_b_resolutions[2].width = 400;
|
||||||
|
a2560k_b_resolutions[2].height = 300;
|
||||||
|
a2560k_b_resolutions[3].width = 640;
|
||||||
|
a2560k_b_resolutions[3].height = 400;
|
||||||
|
a2560k_b_resolutions[4].width = 640;
|
||||||
|
a2560k_b_resolutions[4].height = 480;
|
||||||
|
a2560k_b_resolutions[5].width = 800;
|
||||||
|
a2560k_b_resolutions[5].height = 600;
|
||||||
|
a2560k_b_caps.resolution_count = 6;
|
||||||
|
a2560k_b_caps.resolutions = a2560k_b_resolutions;
|
||||||
|
|
||||||
|
/* Channel B supports 8x8 fonts ONLY */
|
||||||
|
a2560k_b_fonts[0].width = 8;
|
||||||
|
a2560k_b_fonts[0].height = 8;
|
||||||
|
a2560k_b_caps.font_size_count = 1;
|
||||||
|
a2560k_b_caps.font_sizes = a2560k_b_fonts;
|
||||||
|
|
||||||
|
/* Initialize the color lookup tables */
|
||||||
|
for (i = 0; i < VKY3_B_LUT_SIZE; i++) {
|
||||||
|
VKY3_B_TEXT_LUT_FG[i] = a2560k_b_lut[i];
|
||||||
|
VKY3_B_TEXT_LUT_BG[i] = a2560k_b_lut[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the mode to text */
|
||||||
|
txt_a2560k_b_set_mode(TXT_MODE_TEXT);
|
||||||
|
|
||||||
|
/* Set the resolution */
|
||||||
|
txt_a2560k_b_set_resolution(640, 480); /* Default resolution is 640x480 */
|
||||||
|
|
||||||
|
/* Set default colour */
|
||||||
|
#if MODEL_FOENIX_A2560X
|
||||||
|
txt_a2560k_b_set_color(0x0F, 0x08);
|
||||||
|
#else
|
||||||
|
txt_a2560k_b_set_color(0x07, 0x04);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Set the font */
|
||||||
|
txt_a2560k_b_set_font(8, 8, MSX_CP437_8x8_bin); /* Use 8x8 font */
|
||||||
|
|
||||||
|
/* Set the cursor */
|
||||||
|
txt_a2560k_b_set_cursor(1, 0, 0xB1);
|
||||||
|
|
||||||
|
/* Set the border */
|
||||||
|
#if MODEL_FOENIX_A2560X
|
||||||
|
txt_a2560k_b_set_border(8, 8); /* Set up the border */
|
||||||
|
txt_a2560k_b_set_border_color(0x10, 0x00, 0x10);
|
||||||
|
#else
|
||||||
|
txt_a2560k_b_set_border(16, 16); /* Set up the border */
|
||||||
|
txt_a2560k_b_set_border_color(0, 0, 0x3f);
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Enable set_sizes, now that everything is set up initially
|
||||||
|
* And calculate the size of the screen
|
||||||
|
*/
|
||||||
|
a2560k_b_enable_set_sizes = 1;
|
||||||
|
txt_a2560k_b_set_sizes();
|
||||||
|
|
||||||
|
/* Set region to default */
|
||||||
|
region.origin.x = 0;
|
||||||
|
region.origin.y = 0;
|
||||||
|
region.size.width = 0;
|
||||||
|
region.size.height = 0;
|
||||||
|
txt_a2560k_b_set_region(®ion);
|
||||||
|
|
||||||
|
/* Home the cursor */
|
||||||
|
txt_a2560k_b_set_xy(0, 0);
|
||||||
|
|
||||||
|
/* Clear the screen */
|
||||||
|
txt_a2560k_b_fill(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize and install the driver
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
short txt_a2560k_b_install() {
|
||||||
|
t_txt_device device;
|
||||||
|
|
||||||
|
device.number = TXT_SCREEN_A2560K_B;
|
||||||
|
device.name = "SCREEN B";
|
||||||
|
|
||||||
|
device.init = txt_a2560k_b_init;
|
||||||
|
device.get_capabilities = txt_a2560k_b_get_capabilities;
|
||||||
|
device.set_mode = txt_a2560k_b_set_mode;
|
||||||
|
device.set_sizes = txt_a2560k_b_set_sizes;
|
||||||
|
device.set_resolution = txt_a2560k_b_set_resolution;
|
||||||
|
device.set_border = txt_a2560k_b_set_border;
|
||||||
|
device.set_border_color = txt_a2560k_b_set_border_color;
|
||||||
|
device.set_font = txt_a2560k_b_set_font;
|
||||||
|
device.set_cursor = txt_a2560k_b_set_cursor;
|
||||||
|
device.set_cursor_visible = txt_a2560k_b_set_cursor_visible;
|
||||||
|
device.set_region = txt_a2560k_b_set_region;
|
||||||
|
device.get_region = txt_a2560k_b_get_region;
|
||||||
|
device.set_color = txt_a2560k_b_set_color;
|
||||||
|
device.get_color = txt_a2560k_b_get_color;
|
||||||
|
device.set_xy = txt_a2560k_b_set_xy;
|
||||||
|
device.get_xy = txt_a2560k_b_get_xy;
|
||||||
|
device.put = txt_a2560k_b_put;
|
||||||
|
device.scroll = txt_a2560k_b_scroll;
|
||||||
|
device.fill = txt_a2560k_b_fill;
|
||||||
|
device.get_sizes = txt_a2560k_b_get_sizes;
|
||||||
|
|
||||||
|
return txt_register(&device);
|
||||||
|
}
|
19
src/dev/txt_a2560k_b.h
Normal file
19
src/dev/txt_a2560k_b.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/** @file txt_a2560k_b.h
|
||||||
|
*
|
||||||
|
* Text screen driver for A2560K Channel B
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TXT_A2560K_B_H
|
||||||
|
#define __TXT_A2560K_B_H
|
||||||
|
|
||||||
|
/* Channel B is assigned to screen #0, it will be considered the primary channel */
|
||||||
|
#define TXT_SCREEN_A2560K_B 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize and install the driver
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
extern short txt_a2560k_b_install();
|
||||||
|
|
||||||
|
#endif
|
709
src/dev/txt_a2560u.c
Normal file
709
src/dev/txt_a2560u.c
Normal file
|
@ -0,0 +1,709 @@
|
||||||
|
/** @file txt_a2560u.c
|
||||||
|
*
|
||||||
|
* Text screen driver for A2560U
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "constants.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
#include "A2560U/VICKYIII_a2560u.h"
|
||||||
|
#include "dev/txt_screen.h"
|
||||||
|
#include "dev/txt_a2560u.h"
|
||||||
|
|
||||||
|
extern const unsigned char MSX_CP437_8x8_bin[];
|
||||||
|
|
||||||
|
/* Default text color lookup table values (AARRGGBB) */
|
||||||
|
/* 0xGGBB, 0xAARR */
|
||||||
|
const unsigned short a2560u_a_lut[] = {
|
||||||
|
0x0000, 0xFF00, // Black (transparent)
|
||||||
|
0x0000, 0xFF80, // Mid-Tone Red
|
||||||
|
0x8000, 0xFF00, // Mid-Tone Green
|
||||||
|
0x8000, 0xFF80, // Mid-Tone Yellow
|
||||||
|
0x0080, 0xFF00, // Mid-Tone Blue
|
||||||
|
0x5500, 0xFFAA, // Mid-Tone Orange
|
||||||
|
0x8080, 0xFF00, // Mid-Tone Cian
|
||||||
|
0x8080, 0xFF80, // 50% Grey
|
||||||
|
0x5555, 0xFF55, // Dark Grey
|
||||||
|
0x5555, 0xFFFF, // Bright Red
|
||||||
|
0xFF55, 0xFF55, // Bright Green
|
||||||
|
0xFF55, 0xFFFF, // Bright Yellow
|
||||||
|
0x55FF, 0xFF55, // Bright Blue
|
||||||
|
0x7FFF, 0xFFFF, // Bright Orange
|
||||||
|
0xFFFF, 0xFF55, // Bright Cyan
|
||||||
|
0xFFFF, 0xFFFF // White
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver level variables for the screen
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned char a2560u_enable_set_sizes; /* Flag to enable set_sizes to actually do its computation */
|
||||||
|
t_txt_capabilities a2560u_caps; /* The capabilities of Channel A */
|
||||||
|
const t_extent a2560u_resolutions[] = { /* The list of display resolutions */
|
||||||
|
{ 800, 600 },
|
||||||
|
{ 640, 480 },
|
||||||
|
{ 320, 240 } };
|
||||||
|
const t_extent a2560u_fonts[] = { /* The list of supported font resolutions */
|
||||||
|
{ 8, 8 }
|
||||||
|
};
|
||||||
|
t_rect a2560u_region; /* The current region */
|
||||||
|
t_point a2560u_cursor; /* The current cursor position */
|
||||||
|
t_extent a2560u_resolution; /* The current display resolution */
|
||||||
|
t_extent a2560u_font_size; /* The current font size */
|
||||||
|
t_extent a2560u_max_size; /* The size of the screen in characters (without border removed) */
|
||||||
|
t_extent a2560u_visible_size; /* The size of the visible screen in characters (with border removed) */
|
||||||
|
short a2560u_border_width; /* Width of the border on one side */
|
||||||
|
short a2560u_border_height; /* Height of the border on one side */
|
||||||
|
unsigned char a2560u_color; /* The current color */
|
||||||
|
unsigned long msr_shadow; /* A shadow register for the Master Control Register */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the description of a screen's capabilities
|
||||||
|
*
|
||||||
|
* @return a pointer to the read-only description (0 on error)
|
||||||
|
*/
|
||||||
|
const p_txt_capabilities txt_a2560u_get_capabilities() {
|
||||||
|
return &a2560u_caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the size of the text screen in rows and columns so that
|
||||||
|
* the kernel printing routines can work correctly.
|
||||||
|
*
|
||||||
|
* NOTE: this should be called whenever the VKY3 registers are changed
|
||||||
|
*/
|
||||||
|
static void txt_a2560u_set_sizes() {
|
||||||
|
TRACE("txt_a2560u_set_sizes");
|
||||||
|
|
||||||
|
if (a2560u_enable_set_sizes) {
|
||||||
|
/* Only recalculate after initialization is mostly completed */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the maximum number of characters visible on the screen
|
||||||
|
* This controls text layout in memory
|
||||||
|
*/
|
||||||
|
a2560u_max_size.width = a2560u_resolution.width / a2560u_font_size.width;
|
||||||
|
a2560u_max_size.height = a2560u_resolution.height / a2560u_font_size.height;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the characters that are visible in whole or in part
|
||||||
|
*/
|
||||||
|
if ((a2560u_border_width != 0) && (a2560u_border_height != 0)) {
|
||||||
|
short border_width = (2 * a2560u_border_width) / a2560u_font_size.width;
|
||||||
|
short border_height = (2 * a2560u_border_height) / a2560u_font_size.height;
|
||||||
|
|
||||||
|
a2560u_visible_size.width = a2560u_max_size.width - border_width;
|
||||||
|
a2560u_visible_size.height = a2560u_max_size.height - border_height;
|
||||||
|
} else {
|
||||||
|
a2560u_visible_size.width = a2560u_max_size.width;
|
||||||
|
a2560u_visible_size.height = a2560u_max_size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG4("txt_a2560u_set_sizes max:%d,%d, visible:%d,%d", a2560u_max_size.width, a2560u_max_size.height, a2560u_visible_size.width, a2560u_visible_size.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the display resolutions
|
||||||
|
*
|
||||||
|
* @param text_size the size of the screen in visible characters (may be null)
|
||||||
|
* @param pixel_size the size of the screen in pixels (may be null)
|
||||||
|
*/
|
||||||
|
static void txt_a2560u_get_sizes(p_extent text_size, p_extent pixel_size) {
|
||||||
|
if (text_size) {
|
||||||
|
text_size->width = a2560u_visible_size.width;
|
||||||
|
text_size->height = a2560u_visible_size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixel_size) {
|
||||||
|
pixel_size->width = a2560u_resolution.width;
|
||||||
|
pixel_size->height = a2560u_resolution.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the display mode for the screen
|
||||||
|
*
|
||||||
|
* @param mode a bitfield of desired display mode options
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the mode is invalid for the screen
|
||||||
|
*/
|
||||||
|
static short txt_a2560u_set_mode(short mode) {
|
||||||
|
/* Turn off anything not set */
|
||||||
|
msr_shadow &= ~(TXT_MODE_SLEEP | TXT_MODE_TEXT);
|
||||||
|
|
||||||
|
if (mode & TXT_MODE_SLEEP) {
|
||||||
|
/* Put the monitor to sleep */
|
||||||
|
msr_shadow |= VKY3_MCR_BLANK_EN;
|
||||||
|
*MasterControlReg_A = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else if (mode & TXT_MODE_TEXT) {
|
||||||
|
/* Put on text mode */
|
||||||
|
msr_shadow |= VKY3_MCR_TEXT_EN;
|
||||||
|
*MasterControlReg_A = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Unsupported mode */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the display resolution of the screen
|
||||||
|
*
|
||||||
|
* @param width the desired horizontal resolution in pixels
|
||||||
|
* @param height the desired veritical resolution in pixels
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the resolution is unsupported
|
||||||
|
*/
|
||||||
|
static short txt_a2560u_set_resolution(short width, short height) {
|
||||||
|
// If no size specified, set it based on the DIP switch
|
||||||
|
if ((width == 0) || (height == 0)) {
|
||||||
|
if ((*MasterControlReg_A & VKY3_DIP_HIRES) == 0) {
|
||||||
|
width = 800;
|
||||||
|
height = 600;
|
||||||
|
} else {
|
||||||
|
width = 640;
|
||||||
|
height = 480;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char msg[80];
|
||||||
|
sprintf(msg, "Setting resolution %dx%d", width, height);
|
||||||
|
DEBUG(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn off resolution bits */
|
||||||
|
/* TODO: there gotta be a better way to do that */
|
||||||
|
msr_shadow &= ~(VKY3_MCR_RES_MASK);
|
||||||
|
|
||||||
|
if ((width == 800) && (height == 600)) {
|
||||||
|
msr_shadow |= VKY3_MCR_800x600;
|
||||||
|
a2560u_resolution.width = width;
|
||||||
|
a2560u_resolution.height = height;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_a2560u_set_sizes();
|
||||||
|
|
||||||
|
*MasterControlReg_A = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else if ((width == 640) && (height == 480)) {
|
||||||
|
msr_shadow |= VKY3_MCR_640x480;
|
||||||
|
a2560u_resolution.width = width;
|
||||||
|
a2560u_resolution.height = height;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_a2560u_set_sizes();
|
||||||
|
|
||||||
|
*MasterControlReg_A = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if ((width == 320) && (height == 240)) {
|
||||||
|
msr_shadow |= VKY3_MCR_640x480 | VKY3_MCR_DOUBLE_EN;
|
||||||
|
a2560u_resolution.width = width;
|
||||||
|
a2560u_resolution.height = height;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_a2560u_set_sizes();
|
||||||
|
|
||||||
|
*MasterControlReg_A = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Unsupported resolution */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the border of the screen (if supported)
|
||||||
|
*
|
||||||
|
* @param width the horizontal size of one side of the border (0 - 32 pixels)
|
||||||
|
* @param height the vertical size of one side of the border (0 - 32 pixels)
|
||||||
|
*/
|
||||||
|
static void txt_a2560u_set_border(short width, short height) {
|
||||||
|
if ((width > 0) || (height > 0)) {
|
||||||
|
a2560u_border_width = width;
|
||||||
|
a2560u_border_height = height;
|
||||||
|
*BorderControlReg = (height & 0x3f) << 16 | (width & 0x3f) << 8 | VKY3_BRDR_EN;
|
||||||
|
} else {
|
||||||
|
a2560u_border_width = 0;
|
||||||
|
a2560u_border_height = 0;
|
||||||
|
*BorderControlReg = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_a2560u_set_sizes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the border of the screen (if supported)
|
||||||
|
*
|
||||||
|
* @param red the red component of the color (0 - 255)
|
||||||
|
* @param green the green component of the color (0 - 255)
|
||||||
|
* @param blue the blue component of the color (0 - 255)
|
||||||
|
*/
|
||||||
|
static void txt_a2560u_set_border_color(unsigned char red, unsigned char green, unsigned char blue) {
|
||||||
|
*BorderColorReg = (unsigned long)(((red & 0xff) << 16) | ((green & 0xff) << 8) | (blue & 0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a font as the current font for the screen
|
||||||
|
*
|
||||||
|
* @param width width of a character in pixels
|
||||||
|
* @param height of a character in pixels
|
||||||
|
* @param data pointer to the raw font data to be loaded
|
||||||
|
*/
|
||||||
|
static short txt_a2560u_set_font(short width, short height, const unsigned char * data) {
|
||||||
|
if (width == 8 && height == 8) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* The size is valid... set the font */
|
||||||
|
a2560u_font_size.width = width;
|
||||||
|
a2560u_font_size.height = height;
|
||||||
|
|
||||||
|
/* Copy the font data... this assumes a width of one byte! */
|
||||||
|
/* TODO: generalize this for all possible font sizes */
|
||||||
|
for (i = 0; i < 256 * height; i++) {
|
||||||
|
VICKY_TXT_FONT_A[i] = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_a2560u_set_sizes();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the appearance of the cursor
|
||||||
|
*
|
||||||
|
* @param enable 0 to hide, any other number to make visible
|
||||||
|
* @param rate the blink rate for the cursor (0=1s, 1=0.5s, 2=0.25s, 3=1/5s)
|
||||||
|
* @param c the character in the current font to use as a cursor
|
||||||
|
*/
|
||||||
|
static void txt_a2560u_set_cursor(short enable, short rate, char c) {
|
||||||
|
*CursorControlReg = ((a2560u_color & 0xff) << 24) | ((c & 0xff) << 16) | ((rate & 0x03) << 1) | (enable & 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set if the cursor is visible or not
|
||||||
|
*
|
||||||
|
* @param enable 0 to hide, any other number to make visible
|
||||||
|
*/
|
||||||
|
static void txt_a2560u_set_cursor_visible(short enable) {
|
||||||
|
if (enable) {
|
||||||
|
*CursorControlReg |= 0x01;
|
||||||
|
} else {
|
||||||
|
*CursorControlReg &= ~0x01;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the current region
|
||||||
|
*
|
||||||
|
* @param region pointer to a t_rect describing the rectangular region (using character cells for size and size)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the region was invalid
|
||||||
|
*/
|
||||||
|
static short txt_a2560u_get_region(p_rect region) {
|
||||||
|
region->origin.x = a2560u_region.origin.x;
|
||||||
|
region->origin.y = a2560u_region.origin.y;
|
||||||
|
region->size.width = a2560u_region.size.width;
|
||||||
|
region->size.height = a2560u_region.size.height;
|
||||||
|
|
||||||
|
{
|
||||||
|
char msg[80];
|
||||||
|
sprintf(msg,"txt_a2560u_get_region %p: x:%d, y:%d, w:%d, h:%d", region, region->origin.x, region->origin.y, region->size.width, region->size.height);
|
||||||
|
DEBUG(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a region to restrict further character display, scrolling, etc.
|
||||||
|
* Note that a region of zero size will reset the region to the full size of the screen.
|
||||||
|
*
|
||||||
|
* @param region pointer to a t_rect describing the rectangular region (using character cells for size and size)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the region was invalid
|
||||||
|
*/
|
||||||
|
static short txt_a2560u_set_region(const p_rect region) {
|
||||||
|
char msg[80];
|
||||||
|
sprintf(msg,"SET REGION %p x:%d, y:%d, w:%d, h:%d (visible:%d,%d)",
|
||||||
|
region, region->origin.x, region->origin.y, region->size.width, region->size.height, a2560u_visible_size.width, a2560u_visible_size.height);
|
||||||
|
DEBUG(msg);
|
||||||
|
|
||||||
|
if ((region->size.width == 0) || (region->size.height == 0)) {
|
||||||
|
/* Set the region to the default (full screen) */
|
||||||
|
a2560u_region.origin.x = 0;
|
||||||
|
a2560u_region.origin.y = 0;
|
||||||
|
a2560u_region.size.width = a2560u_visible_size.width;
|
||||||
|
a2560u_region.size.height = a2560u_visible_size.height;
|
||||||
|
} else {
|
||||||
|
a2560u_region.origin.x = region->origin.x;
|
||||||
|
a2560u_region.origin.y = region->origin.y;
|
||||||
|
a2560u_region.size.width = region->size.width;
|
||||||
|
a2560u_region.size.height = region->size.height;
|
||||||
|
|
||||||
|
//sprintf(msg,"specific region %d %d %d %d", region->origin.x, region->origin.y, region->size.width, region->size.height);
|
||||||
|
//DEBUG(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
sprintf(msg,"txt_a2560u_set_region: NEW REGION %p x:%d, y:%d, w:%d, h:%d (visible:%d,%d)",
|
||||||
|
region, region->origin.x, region->origin.y, region->size.width, region->size.height, a2560u_visible_size.width, a2560u_visible_size.height);
|
||||||
|
//DEBUG(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default foreground and background colors for printing
|
||||||
|
*
|
||||||
|
* @param pointer to the foreground the Text LUT index of the new current foreground color (0 - 15)
|
||||||
|
* @param pointer to the background the Text LUT index of the new current background color (0 - 15)
|
||||||
|
*/
|
||||||
|
static short txt_a2560u_get_color(unsigned char * foreground, unsigned char * background) {
|
||||||
|
*foreground = (a2560u_color & 0xf0) >> 4;
|
||||||
|
*background = a2560u_color & 0x0f;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default foreground and background colors for printing
|
||||||
|
*
|
||||||
|
* @param foreground the Text LUT index of the new current foreground color (0 - 15)
|
||||||
|
* @param background the Text LUT index of the new current background color (0 - 15)
|
||||||
|
*/
|
||||||
|
static short txt_a2560u_set_color(unsigned char foreground, unsigned char background) {
|
||||||
|
a2560u_color = ((foreground & 0x0f) << 4) + (background & 0x0f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This works around a bug in the A2560U's FPGA where reading bytes of text memory
|
||||||
|
* (possibly color as well ?) are inverted. Ie if the memory contains AB, A beint on an
|
||||||
|
* even address, then when reading A you'll get B and reading B you'll get A. This
|
||||||
|
* functions can be removed if the FPGA is corrected. */
|
||||||
|
static char read_swapped_byte(char *addr) {
|
||||||
|
if ((long)addr & 1) {
|
||||||
|
short w = *(short*)(addr-1);
|
||||||
|
return (char)w;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
short w = *(short*)(addr);
|
||||||
|
return ((char*)&w)[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll the text in the current region
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param horizontal the number of columns to scroll (negative is left, positive is right)
|
||||||
|
* @param vertical the number of rows to scroll (negative is down, positive is up)
|
||||||
|
*/
|
||||||
|
static void txt_a2560u_scroll(short horizontal, short vertical) {
|
||||||
|
short x, x0, x1, x2, x3, dx;
|
||||||
|
short y, y0, y1, y2, y3, dy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine limits of rectangles to move and fill and directions of loops
|
||||||
|
* x0 and y0 are the positions of the first cell to be over-written
|
||||||
|
* x1 and y1 are the positions of the first cell to be copied... TEXT[x0,y0] := TEXT[x1,y1]
|
||||||
|
* x2 and y2 are the position of the last cell to be over-written
|
||||||
|
* x3 and y3 are the position of the last cell to be copied... TEXT[x2,y2] := TEXT[x3,y3]
|
||||||
|
*
|
||||||
|
* When blanking, the rectangles (x2,y0) - (x3,y3) and (x0,y2) - (x2,y3) are cleared
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Determine the row limits
|
||||||
|
|
||||||
|
if (vertical >= 0) {
|
||||||
|
y0 = a2560u_region.origin.y;
|
||||||
|
y1 = y0 + vertical;
|
||||||
|
y3 = a2560u_region.origin.y + a2560u_region.size.height;
|
||||||
|
y2 = y3 - vertical;
|
||||||
|
dy = 1;
|
||||||
|
} else {
|
||||||
|
y0 = a2560u_region.origin.y + a2560u_region.size.height - 1;
|
||||||
|
y1 = y0 + vertical;
|
||||||
|
y3 = a2560u_region.origin.y - 1;
|
||||||
|
y2 = y3 - vertical;
|
||||||
|
dy = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the column limits
|
||||||
|
|
||||||
|
if (horizontal >= 0) {
|
||||||
|
x0 = a2560u_region.origin.x;
|
||||||
|
x1 = x0 + horizontal;
|
||||||
|
x3 = a2560u_region.origin.x + a2560u_region.size.width;
|
||||||
|
x2 = x3 - horizontal;
|
||||||
|
dx = 1;
|
||||||
|
} else {
|
||||||
|
x0 = a2560u_region.origin.x + a2560u_region.size.width - 1;
|
||||||
|
x1 = x0 + horizontal;
|
||||||
|
x3 = a2560u_region.origin.x - 1;
|
||||||
|
x2 = x3 - horizontal;
|
||||||
|
dx = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the rectangle. We can't copy byte by byte, they get swapped (FPGA bug) */
|
||||||
|
char * const text_mem = (char*)ScreenText_A;
|
||||||
|
char * const color_mem = (char*)ColorText_A;
|
||||||
|
|
||||||
|
int delta_y = dy * a2560u_max_size.width;
|
||||||
|
int row_dst = y0 * a2560u_max_size.width - delta_y;
|
||||||
|
int row_src = y0 * a2560u_max_size.width + vertical * a2560u_max_size.width - delta_y;
|
||||||
|
for (y = y0; y != y2; y += dy) {
|
||||||
|
row_dst += delta_y;
|
||||||
|
row_src += delta_y;
|
||||||
|
int offset_dst = row_dst + x0 - dx;
|
||||||
|
int offset_src = row_src + horizontal + x0 - dx;
|
||||||
|
for (x = x0; x != x2; x += dx) {
|
||||||
|
offset_dst += dx;
|
||||||
|
offset_src += dx;
|
||||||
|
ScreenText_A[offset_dst] = read_swapped_byte(&ScreenText_A[offset_src]);
|
||||||
|
ColorText_A[offset_dst] = read_swapped_byte(&ColorText_A[offset_src]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the rectangles */
|
||||||
|
if (horizontal != 0) {
|
||||||
|
row_dst = y0 * a2560u_max_size.width - delta_y;
|
||||||
|
for (y = y0; y != y3; y += dy) {
|
||||||
|
row_dst += delta_y;
|
||||||
|
for (x = x2; x != x3; x += dx) {
|
||||||
|
ScreenText_A[row_dst + x] = ' ';
|
||||||
|
ColorText_A[row_dst + x] = a2560u_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertical != 0) {
|
||||||
|
row_dst = y2 * a2560u_max_size.width - delta_y;
|
||||||
|
for (y = y2; y != y3; y += dy) {
|
||||||
|
row_dst += delta_y;
|
||||||
|
for (x = x0; x != x3; x += dx) {
|
||||||
|
ScreenText_A[row_dst + x] = ' ';
|
||||||
|
ColorText_A[row_dst + x] = a2560u_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the current region with a character in the current color
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param c the character to fill the region with
|
||||||
|
*/
|
||||||
|
static void txt_a2560u_fill(char c) {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
for (y = 0; y < a2560u_region.size.height; y++) {
|
||||||
|
int offset_row = (a2560u_region.origin.y + y) * a2560u_max_size.width;
|
||||||
|
for (x = 0; x < a2560u_region.size.width; x++) {
|
||||||
|
int offset = offset_row + a2560u_region.origin.x + x;
|
||||||
|
ScreenText_A[offset] = c;
|
||||||
|
ColorText_A[offset] = a2560u_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the position of the cursor to (x, y) relative to the current region
|
||||||
|
* If the (x, y) coordinate is outside the region, it will be clipped to the region.
|
||||||
|
* If y is greater than the height of the region, the region will scroll until that relative
|
||||||
|
* position would be within view.
|
||||||
|
*
|
||||||
|
* @param x the column for the cursor
|
||||||
|
* @param y the row for the cursor
|
||||||
|
*/
|
||||||
|
static void txt_a2560u_set_xy(short x, short y) {
|
||||||
|
/* Make sure X is within range for the current region... "print" a newline if not */
|
||||||
|
if (x < 0) {
|
||||||
|
x = 0;
|
||||||
|
} else if (x >= a2560u_region.size.width) {
|
||||||
|
x = 0;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure Y is within range for the current region... scroll if not */
|
||||||
|
if (y < 0) {
|
||||||
|
y = 0;
|
||||||
|
} else if (y >= a2560u_region.size.height) {
|
||||||
|
txt_a2560u_scroll(0, y - a2560u_region.size.height + 1);
|
||||||
|
y = a2560u_region.size.height - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
a2560u_cursor.x = x;
|
||||||
|
a2560u_cursor.y = y;
|
||||||
|
|
||||||
|
/* Set register */
|
||||||
|
*CursorPositionReg = (((a2560u_region.origin.y + y) & 0xffff) << 16) | ((a2560u_region.origin.x + x) & 0xffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position of the cursor (x, y) relative to the current region
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param position pointer to a t_point record to fill out
|
||||||
|
*/
|
||||||
|
static void txt_a2560u_get_xy(p_point position) {
|
||||||
|
position->x = a2560u_cursor.x;
|
||||||
|
position->y = a2560u_cursor.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a character to the current cursor position in the current color
|
||||||
|
*
|
||||||
|
* @param c the character to print
|
||||||
|
*/
|
||||||
|
static void txt_a2560u_put(char c) {
|
||||||
|
short x;
|
||||||
|
short y;
|
||||||
|
unsigned int offset;
|
||||||
|
|
||||||
|
x = a2560u_region.origin.x + a2560u_cursor.x;
|
||||||
|
y = a2560u_region.origin.y + a2560u_cursor.y;
|
||||||
|
offset = y * a2560u_max_size.width + x;
|
||||||
|
ScreenText_A[offset] = c;
|
||||||
|
ColorText_A[offset] = a2560u_color;
|
||||||
|
|
||||||
|
txt_a2560u_set_xy(a2560u_cursor.x + 1, a2560u_cursor.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the screen
|
||||||
|
*/
|
||||||
|
static void txt_a2560u_init() {
|
||||||
|
char buffer[255];
|
||||||
|
t_rect region;
|
||||||
|
int i;
|
||||||
|
DEBUG("txt_a2560u_init");
|
||||||
|
a2560u_resolution.width = 0;
|
||||||
|
a2560u_resolution.height = 0;
|
||||||
|
a2560u_visible_size.width = 0;
|
||||||
|
a2560u_visible_size.height = 0;
|
||||||
|
a2560u_font_size.width = 0;
|
||||||
|
a2560u_font_size.height = 0;
|
||||||
|
|
||||||
|
/* Disable the set_sizes call for now, to avoid computing transcient unnecessary values */
|
||||||
|
a2560u_enable_set_sizes = 0;
|
||||||
|
|
||||||
|
/* Start with nothing on */
|
||||||
|
msr_shadow = 0;
|
||||||
|
|
||||||
|
/* Define the capabilities */
|
||||||
|
|
||||||
|
/* Specify the screen number. We have only one so... */
|
||||||
|
a2560u_caps.number = TXT_SCREEN_A2560U;
|
||||||
|
|
||||||
|
/* This screen can be text, bitmap or can be put to sleep */
|
||||||
|
a2560u_caps.supported_modes = TXT_MODE_TEXT | TXT_MODE_SPRITE | TXT_MODE_BITMAP | TXT_MODE_TILE | TXT_MODE_SLEEP;
|
||||||
|
|
||||||
|
/* Supported resolutions */
|
||||||
|
a2560u_caps.resolution_count = sizeof(a2560u_resolutions) / sizeof(t_extent);
|
||||||
|
a2560u_caps.resolutions = a2560u_resolutions;
|
||||||
|
|
||||||
|
/* Only 8x8 on the U */
|
||||||
|
a2560u_caps.font_size_count = sizeof(a2560u_fonts) / sizeof(t_extent);
|
||||||
|
a2560u_caps.font_sizes = a2560u_fonts;
|
||||||
|
|
||||||
|
/* Initialize the color lookup tables */
|
||||||
|
for (i = 0; i < sizeof(a2560u_a_lut)/sizeof(unsigned short); i++) {
|
||||||
|
FG_CLUT_A[i] = a2560u_a_lut[i];
|
||||||
|
BG_CLUT_A[i] = a2560u_a_lut[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the mode to text */
|
||||||
|
txt_a2560u_set_mode(TXT_MODE_TEXT);
|
||||||
|
|
||||||
|
/* Set the resolution */
|
||||||
|
txt_a2560u_set_resolution(0, 0); /* Default resolution depends on HIRES dip switch */
|
||||||
|
|
||||||
|
/* Set the default color: light grey on blue */
|
||||||
|
txt_a2560u_set_color(0x07, 0x04);
|
||||||
|
|
||||||
|
/* Set the font */
|
||||||
|
txt_a2560u_set_font(8, 8, MSX_CP437_8x8_bin); /* Use 8x8 font */
|
||||||
|
|
||||||
|
/* Set the cursor */
|
||||||
|
txt_a2560u_set_cursor(1, 0, 0xB1);
|
||||||
|
|
||||||
|
/* Set the border */
|
||||||
|
txt_a2560u_set_border(16, 16); /* Set up the border */
|
||||||
|
txt_a2560u_set_border_color(0, 0, 0x3f);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable set_sizes, now that everything is set up initially
|
||||||
|
* And calculate the size of the screen
|
||||||
|
*/
|
||||||
|
a2560u_enable_set_sizes = 1;
|
||||||
|
txt_a2560u_set_sizes();
|
||||||
|
|
||||||
|
/* Set region to default */
|
||||||
|
region.origin.x = 0;
|
||||||
|
region.origin.y = 0;
|
||||||
|
region.size.width = 0;
|
||||||
|
region.size.height = 0;
|
||||||
|
txt_a2560u_set_region(®ion);
|
||||||
|
|
||||||
|
/* Home the cursor */
|
||||||
|
txt_a2560u_set_xy(0, 0);
|
||||||
|
|
||||||
|
/* Clear the screen */
|
||||||
|
txt_a2560u_fill(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_txt_device device;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize and install the driver
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
short txt_a2560u_install() {
|
||||||
|
t_txt_device device;
|
||||||
|
|
||||||
|
device.number = TXT_SCREEN_A2560U;
|
||||||
|
device.name = "SCREEN";
|
||||||
|
|
||||||
|
device.init = txt_a2560u_init;
|
||||||
|
device.get_capabilities = txt_a2560u_get_capabilities;
|
||||||
|
device.set_mode = txt_a2560u_set_mode;
|
||||||
|
device.set_sizes = txt_a2560u_set_sizes;
|
||||||
|
device.set_resolution = txt_a2560u_set_resolution;
|
||||||
|
device.set_border = txt_a2560u_set_border;
|
||||||
|
device.set_border_color = txt_a2560u_set_border_color;
|
||||||
|
device.set_font = txt_a2560u_set_font;
|
||||||
|
device.set_cursor = txt_a2560u_set_cursor;
|
||||||
|
device.set_cursor_visible = txt_a2560u_set_cursor_visible;
|
||||||
|
device.get_region = txt_a2560u_get_region;
|
||||||
|
device.set_region = txt_a2560u_set_region;
|
||||||
|
device.get_color = txt_a2560u_get_color;
|
||||||
|
device.set_color = txt_a2560u_set_color;
|
||||||
|
device.set_xy = txt_a2560u_set_xy;
|
||||||
|
device.get_xy = txt_a2560u_get_xy;
|
||||||
|
device.put = txt_a2560u_put;
|
||||||
|
device.scroll = txt_a2560u_scroll;
|
||||||
|
device.fill = txt_a2560u_fill;
|
||||||
|
device.get_sizes = txt_a2560u_get_sizes;
|
||||||
|
|
||||||
|
return txt_register(&device);
|
||||||
|
}
|
19
src/dev/txt_a2560u.h
Normal file
19
src/dev/txt_a2560u.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/** @file txt_a2560u.h
|
||||||
|
*
|
||||||
|
* Text screen driver for the A2560U
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TXT_A2560U_H
|
||||||
|
#define __TXT_A2560U_H
|
||||||
|
|
||||||
|
/* We only have one screen */
|
||||||
|
#define TXT_SCREEN_A2560U 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize and install the driver
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
extern short txt_a2560u_install();
|
||||||
|
|
||||||
|
#endif
|
694
src/dev/txt_c256.c
Normal file
694
src/dev/txt_c256.c
Normal file
|
@ -0,0 +1,694 @@
|
||||||
|
/** @file txt_c256.c
|
||||||
|
*
|
||||||
|
* Text screen driver for c256
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "C256/vicky_ii.h"
|
||||||
|
#include "dev/txt_c256.h"
|
||||||
|
#include "dev/txt_screen.h"
|
||||||
|
|
||||||
|
extern const unsigned char MSX_CP437_8x8_bin[];
|
||||||
|
|
||||||
|
const t_color4 c256_clut[] = {
|
||||||
|
{0, 0, 0}, // 0: Black
|
||||||
|
{0, 0, 128}, // 1: Red
|
||||||
|
{0, 128, 0}, // 2: Green
|
||||||
|
{0, 128, 128}, // 3: Yellow
|
||||||
|
{128, 0, 0}, // 4: Blue
|
||||||
|
{128, 0, 128}, // 5: Magenta
|
||||||
|
{128, 128, 0}, // 6: Cyan
|
||||||
|
{192, 192, 192}, // 7: White
|
||||||
|
{128, 128, 128}, // 8: Bright Gray
|
||||||
|
{0, 0, 255}, // 9: Bright Red
|
||||||
|
{0, 255, 0}, // A: Bright Green
|
||||||
|
{0, 255, 255}, // B: Bright Yellow
|
||||||
|
{255, 0, 0}, // C: Bright Blue
|
||||||
|
{255, 0, 255}, // D: Bright Magenta
|
||||||
|
{255, 255, 0}, // E: Bright Cyan
|
||||||
|
{255, 255, 255} // F: Bright White
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver level variables for the screen
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned char c256_enable_set_sizes; /* Flag to enable set_sizes to actually do its computation */
|
||||||
|
|
||||||
|
t_txt_capabilities c256_caps; /* The capabilities of Channel A */
|
||||||
|
|
||||||
|
t_extent c256_resolutions[] = { /* The list of display resolutions */
|
||||||
|
{ 800, 600 },
|
||||||
|
{ 400, 300 },
|
||||||
|
{ 640, 480 },
|
||||||
|
{ 320, 240 }
|
||||||
|
};
|
||||||
|
|
||||||
|
t_extent c256_fonts[] = { /* The list of supported font resolutions */
|
||||||
|
{ 8, 8 }
|
||||||
|
};
|
||||||
|
|
||||||
|
t_rect c256_region; /* The current region */
|
||||||
|
t_point c256_cursor; /* The current cursor position */
|
||||||
|
t_extent c256_resolution; /* The current display resolution */
|
||||||
|
t_extent c256_font_size; /* The current font size */
|
||||||
|
t_extent c256_max_size; /* The size of the screen in characters (without border removed) */
|
||||||
|
t_extent c256_visible_size; /* The size of the visible screen in characters (with border removed) */
|
||||||
|
short c256_border_width; /* Width of the border on one side */
|
||||||
|
short c256_border_height; /* Height of the border on one side */
|
||||||
|
unsigned char c256_color; /* The current color */
|
||||||
|
unsigned long msr_shadow; /* A shadow register for the Master Control Register */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the description of a screen's capabilities
|
||||||
|
*
|
||||||
|
* @return a pointer to the read-only description (0 on error)
|
||||||
|
*/
|
||||||
|
const p_txt_capabilities txt_c256_get_capabilities() {
|
||||||
|
return &c256_caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the size of the text screen in rows and columns so that
|
||||||
|
* the kernel printing routines can work correctly.
|
||||||
|
*
|
||||||
|
* NOTE: this should be called whenever the VKY3 registers are changed
|
||||||
|
*/
|
||||||
|
static void txt_c256_set_sizes() {
|
||||||
|
TRACE("txt_c256_set_sizes");
|
||||||
|
|
||||||
|
if (c256_enable_set_sizes) {
|
||||||
|
/* Only recalculate after initialization is mostly completed */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the maximum number of characters visible on the screen
|
||||||
|
* This controls text layout in memory
|
||||||
|
*/
|
||||||
|
c256_max_size.width = c256_resolution.width / c256_font_size.width;
|
||||||
|
c256_max_size.height = c256_resolution.height / c256_font_size.height;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the characters that are visible in whole or in part
|
||||||
|
*/
|
||||||
|
if ((c256_border_width != 0) && (c256_border_height != 0)) {
|
||||||
|
short border_width = (2 * c256_border_width) / c256_font_size.width;
|
||||||
|
short border_height = (2 * c256_border_height) / c256_font_size.height;
|
||||||
|
|
||||||
|
c256_visible_size.width = c256_max_size.width - border_width;
|
||||||
|
c256_visible_size.height = c256_max_size.height - border_height;
|
||||||
|
} else {
|
||||||
|
c256_visible_size.width = c256_max_size.width;
|
||||||
|
c256_visible_size.height = c256_max_size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG4("txt_c256_set_sizes max:%d,%d, visible:%d,%d", c256_max_size.width, c256_max_size.height, c256_visible_size.width, c256_visible_size.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the display resolutions
|
||||||
|
*
|
||||||
|
* @param text_size the size of the screen in visible characters (may be null)
|
||||||
|
* @param pixel_size the size of the screen in pixels (may be null)
|
||||||
|
*/
|
||||||
|
static void txt_c256_get_sizes(p_extent text_size, p_extent pixel_size) {
|
||||||
|
if (text_size) {
|
||||||
|
text_size->width = c256_visible_size.width;
|
||||||
|
text_size->height = c256_visible_size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixel_size) {
|
||||||
|
pixel_size->width = c256_resolution.width;
|
||||||
|
pixel_size->height = c256_resolution.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the display mode for the screen
|
||||||
|
*
|
||||||
|
* @param mode a bitfield of desired display mode options
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the mode is invalid for the screen
|
||||||
|
*/
|
||||||
|
static short txt_c256_set_mode(short mode) {
|
||||||
|
/* Turn off anything not set */
|
||||||
|
msr_shadow &= ~(TXT_MODE_SLEEP | TXT_MODE_TEXT);
|
||||||
|
|
||||||
|
if (mode & TXT_MODE_SLEEP) {
|
||||||
|
/* Put the monitor to sleep */
|
||||||
|
msr_shadow |= VKY_MCR_DISABLE;
|
||||||
|
tvky_mstr_ctrl->raw = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else if (mode & TXT_MODE_TEXT) {
|
||||||
|
/* Put on text mode */
|
||||||
|
msr_shadow |= VKY_MCR_TEXT;
|
||||||
|
tvky_mstr_ctrl->raw = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Unsupported mode */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the display resolution of the screen
|
||||||
|
*
|
||||||
|
* @param width the desired horizontal resolution in pixels
|
||||||
|
* @param height the desired veritical resolution in pixels
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the resolution is unsupported
|
||||||
|
*/
|
||||||
|
static short txt_c256_set_resolution(short width, short height) {
|
||||||
|
// TODO: If no size specified, set it based on the DIP switch
|
||||||
|
|
||||||
|
|
||||||
|
/* Turn off resolution bits */
|
||||||
|
/* TODO: there gotta be a better way to do that */
|
||||||
|
msr_shadow &= ~(VKY_MCR_RES_MASK);
|
||||||
|
|
||||||
|
if ((width == 800) && (height == 600)) {
|
||||||
|
msr_shadow |= VKY_MCR_RES_800x600;
|
||||||
|
c256_resolution.width = width;
|
||||||
|
c256_resolution.height = height;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_c256_set_sizes();
|
||||||
|
|
||||||
|
tvky_mstr_ctrl->raw = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else if ((width == 640) && (height == 480)) {
|
||||||
|
msr_shadow |= VKY_MCR_RES_640x480;
|
||||||
|
c256_resolution.width = width;
|
||||||
|
c256_resolution.height = height;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_c256_set_sizes();
|
||||||
|
|
||||||
|
tvky_mstr_ctrl->raw = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if ((width == 320) && (height == 240)) {
|
||||||
|
msr_shadow |= VKY_MCR_RES_320x240;
|
||||||
|
c256_resolution.width = width;
|
||||||
|
c256_resolution.height = height;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_c256_set_sizes();
|
||||||
|
|
||||||
|
tvky_mstr_ctrl->raw = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if ((width == 400) && (height == 300)) {
|
||||||
|
msr_shadow |= VKY_MCR_RES_400x300;
|
||||||
|
c256_resolution.width = width;
|
||||||
|
c256_resolution.height = height;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_c256_set_sizes();
|
||||||
|
|
||||||
|
tvky_mstr_ctrl->raw = msr_shadow;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Unsupported resolution */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the border of the screen (if supported)
|
||||||
|
*
|
||||||
|
* @param width the horizontal size of one side of the border (0 - 32 pixels)
|
||||||
|
* @param height the vertical size of one side of the border (0 - 32 pixels)
|
||||||
|
*/
|
||||||
|
static void txt_c256_set_border(short width, short height) {
|
||||||
|
if ((width > 0) || (height > 0)) {
|
||||||
|
c256_border_width = width;
|
||||||
|
c256_border_height = height;
|
||||||
|
tvky_brdr_ctrl->control = 0x01;
|
||||||
|
tvky_brdr_ctrl->size_x = width;
|
||||||
|
tvky_brdr_ctrl->sizy_y = height;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
tvky_brdr_ctrl->control = 0;
|
||||||
|
tvky_brdr_ctrl->size_x = 0;
|
||||||
|
tvky_brdr_ctrl->sizy_y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_c256_set_sizes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the border of the screen (if supported)
|
||||||
|
*
|
||||||
|
* @param red the red component of the color (0 - 255)
|
||||||
|
* @param green the green component of the color (0 - 255)
|
||||||
|
* @param blue the blue component of the color (0 - 255)
|
||||||
|
*/
|
||||||
|
static void txt_c256_set_border_color(unsigned char red, unsigned char green, unsigned char blue) {
|
||||||
|
tvky_brdr_ctrl->color.red = red;
|
||||||
|
tvky_brdr_ctrl->color.green = green;
|
||||||
|
tvky_brdr_ctrl->color.blue = blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a font as the current font for the screen
|
||||||
|
*
|
||||||
|
* @param width width of a character in pixels
|
||||||
|
* @param height of a character in pixels
|
||||||
|
* @param data pointer to the raw font data to be loaded
|
||||||
|
*/
|
||||||
|
static short txt_c256_set_font(short width, short height, const unsigned char * data) {
|
||||||
|
if (width == 8 && height == 8) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* The size is valid... set the font */
|
||||||
|
c256_font_size.width = width;
|
||||||
|
c256_font_size.height = height;
|
||||||
|
|
||||||
|
/* Copy the font data... this assumes a width of one byte! */
|
||||||
|
/* TODO: generalize this for all possible font sizes */
|
||||||
|
for (i = 0; i < 256 * height; i++) {
|
||||||
|
tvky_font_set_0[i] = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_c256_set_sizes();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the appearance of the cursor
|
||||||
|
*
|
||||||
|
* @param enable 0 to hide, any other number to make visible
|
||||||
|
* @param rate the blink rate for the cursor (0=1s, 1=0.5s, 2=0.25s, 3=1/5s)
|
||||||
|
* @param c the character in the current font to use as a cursor
|
||||||
|
*/
|
||||||
|
static void txt_c256_set_cursor(short enable, short rate, char c) {
|
||||||
|
tvky_crsr_ctrl->control = ((rate & 0x03) << 1) | ((enable) ? 1 : 0);
|
||||||
|
tvky_crsr_ctrl->character = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set if the cursor is visible or not
|
||||||
|
*
|
||||||
|
* @param enable 0 to hide, any other number to make visible
|
||||||
|
*/
|
||||||
|
static void txt_c256_set_cursor_visible(short enable) {
|
||||||
|
if (enable) {
|
||||||
|
tvky_crsr_ctrl->control |= 0x01;
|
||||||
|
} else {
|
||||||
|
tvky_crsr_ctrl->control &= ~0x01;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the current region
|
||||||
|
*
|
||||||
|
* @param region pointer to a t_rect describing the rectangular region (using character cells for size and size)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the region was invalid
|
||||||
|
*/
|
||||||
|
static short txt_c256_get_region(p_rect region) {
|
||||||
|
region->origin.x = c256_region.origin.x;
|
||||||
|
region->origin.y = c256_region.origin.y;
|
||||||
|
region->size.width = c256_region.size.width;
|
||||||
|
region->size.height = c256_region.size.height;
|
||||||
|
|
||||||
|
{
|
||||||
|
char msg[80];
|
||||||
|
sprintf(msg,"txt_c256_get_region %p: x:%d, y:%d, w:%d, h:%d", region, region->origin.x, region->origin.y, region->size.width, region->size.height);
|
||||||
|
DEBUG(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a region to restrict further character display, scrolling, etc.
|
||||||
|
* Note that a region of zero size will reset the region to the full size of the screen.
|
||||||
|
*
|
||||||
|
* @param region pointer to a t_rect describing the rectangular region (using character cells for size and size)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the region was invalid
|
||||||
|
*/
|
||||||
|
static short txt_c256_set_region(const p_rect region) {
|
||||||
|
// char msg[80];
|
||||||
|
// sprintf(msg,"SET REGION %p x:%d, y:%d, w:%d, h:%d (visible:%d,%d)",
|
||||||
|
// region, region->origin.x, region->origin.y, region->size.width, region->size.height, c256_visible_size.width, c256_visible_size.height);
|
||||||
|
// DEBUG(msg);
|
||||||
|
|
||||||
|
if ((region->size.width == 0) || (region->size.height == 0)) {
|
||||||
|
/* Set the region to the default (full screen) */
|
||||||
|
c256_region.origin.x = 0;
|
||||||
|
c256_region.origin.y = 0;
|
||||||
|
c256_region.size.width = c256_visible_size.width;
|
||||||
|
c256_region.size.height = c256_visible_size.height;
|
||||||
|
} else {
|
||||||
|
c256_region.origin.x = region->origin.x;
|
||||||
|
c256_region.origin.y = region->origin.y;
|
||||||
|
c256_region.size.width = region->size.width;
|
||||||
|
c256_region.size.height = region->size.height;
|
||||||
|
|
||||||
|
//sprintf(msg,"specific region %d %d %d %d", region->origin.x, region->origin.y, region->size.width, region->size.height);
|
||||||
|
//DEBUG(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
//sprintf(msg,"txt_c256_set_region: NEW REGION %p x:%d, y:%d, w:%d, h:%d (visible:%d,%d)",
|
||||||
|
//region, region->origin.x, region->origin.y, region->size.width, region->size.height, c256_visible_size.width, c256_visible_size.height);
|
||||||
|
//DEBUG(msg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default foreground and background colors for printing
|
||||||
|
*
|
||||||
|
* @param pointer to the foreground the Text LUT index of the new current foreground color (0 - 15)
|
||||||
|
* @param pointer to the background the Text LUT index of the new current background color (0 - 15)
|
||||||
|
*/
|
||||||
|
static short txt_c256_get_color(unsigned char * foreground, unsigned char * background) {
|
||||||
|
*foreground = (c256_color & 0xf0) >> 4;
|
||||||
|
*background = c256_color & 0x0f;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default foreground and background colors for printing
|
||||||
|
*
|
||||||
|
* @param foreground the Text LUT index of the new current foreground color (0 - 15)
|
||||||
|
* @param background the Text LUT index of the new current background color (0 - 15)
|
||||||
|
*/
|
||||||
|
static short txt_c256_set_color(unsigned char foreground, unsigned char background) {
|
||||||
|
c256_color = ((foreground & 0x0f) << 4) + (background & 0x0f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll the text in the current region
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param horizontal the number of columns to scroll (negative is left, positive is right)
|
||||||
|
* @param vertical the number of rows to scroll (negative is down, positive is up)
|
||||||
|
*/
|
||||||
|
static void txt_c256_scroll(short horizontal, short vertical) {
|
||||||
|
short x, x0, x1, x2, x3, dx;
|
||||||
|
short y, y0, y1, y2, y3, dy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine limits of rectangles to move and fill and directions of loops
|
||||||
|
* x0 and y0 are the positions of the first cell to be over-written
|
||||||
|
* x1 and y1 are the positions of the first cell to be copied... TEXT[x0,y0] := TEXT[x1,y1]
|
||||||
|
* x2 and y2 are the position of the last cell to be over-written
|
||||||
|
* x3 and y3 are the position of the last cell to be copied... TEXT[x2,y2] := TEXT[x3,y3]
|
||||||
|
*
|
||||||
|
* When blanking, the rectangles (x2,y0) - (x3,y3) and (x0,y2) - (x2,y3) are cleared
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Determine the row limits
|
||||||
|
|
||||||
|
if (vertical >= 0) {
|
||||||
|
y0 = c256_region.origin.y;
|
||||||
|
y1 = y0 + vertical;
|
||||||
|
y3 = c256_region.origin.y + c256_region.size.height;
|
||||||
|
y2 = y3 - vertical;
|
||||||
|
dy = 1;
|
||||||
|
} else {
|
||||||
|
y0 = c256_region.origin.y + c256_region.size.height - 1;
|
||||||
|
y1 = y0 + vertical;
|
||||||
|
y3 = c256_region.origin.y - 1;
|
||||||
|
y2 = y3 - vertical;
|
||||||
|
dy = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the column limits
|
||||||
|
|
||||||
|
if (horizontal >= 0) {
|
||||||
|
x0 = c256_region.origin.x;
|
||||||
|
x1 = x0 + horizontal;
|
||||||
|
x3 = c256_region.origin.x + c256_region.size.width;
|
||||||
|
x2 = x3 - horizontal;
|
||||||
|
dx = 1;
|
||||||
|
} else {
|
||||||
|
x0 = c256_region.origin.x + c256_region.size.width - 1;
|
||||||
|
x1 = x0 + horizontal;
|
||||||
|
x3 = c256_region.origin.x - 1;
|
||||||
|
x2 = x3 - horizontal;
|
||||||
|
dx = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the rectangle. */
|
||||||
|
int delta_y = dy * c256_max_size.width;
|
||||||
|
int row_dst = y0 * c256_max_size.width - delta_y;
|
||||||
|
int row_src = y0 * c256_max_size.width + vertical * c256_max_size.width - delta_y;
|
||||||
|
for (y = y0; y != y2; y += dy) {
|
||||||
|
row_dst += delta_y;
|
||||||
|
row_src += delta_y;
|
||||||
|
int offset_dst = row_dst + x0 - dx;
|
||||||
|
int offset_src = row_src + horizontal + x0 - dx;
|
||||||
|
for (x = x0; x != x2; x += dx) {
|
||||||
|
offset_dst += dx;
|
||||||
|
offset_src += dx;
|
||||||
|
tvky_text_matrix[offset_dst] = tvky_text_matrix[offset_src];
|
||||||
|
tvky_color_matrix[offset_dst] = tvky_color_matrix[offset_src];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the rectangles */
|
||||||
|
if (horizontal != 0) {
|
||||||
|
row_dst = y0 * c256_max_size.width - delta_y;
|
||||||
|
for (y = y0; y != y3; y += dy) {
|
||||||
|
row_dst += delta_y;
|
||||||
|
for (x = x2; x != x3; x += dx) {
|
||||||
|
tvky_text_matrix[row_dst + x] = ' ';
|
||||||
|
tvky_color_matrix[row_dst + x] = c256_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertical != 0) {
|
||||||
|
row_dst = y2 * c256_max_size.width - delta_y;
|
||||||
|
for (y = y2; y != y3; y += dy) {
|
||||||
|
row_dst += delta_y;
|
||||||
|
for (x = x0; x != x3; x += dx) {
|
||||||
|
tvky_text_matrix[row_dst + x] = ' ';
|
||||||
|
tvky_color_matrix[row_dst + x] = c256_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the current region with a character in the current color
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param c the character to fill the region with
|
||||||
|
*/
|
||||||
|
static void txt_c256_fill(char c) {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
for (y = 0; y < c256_region.size.height; y++) {
|
||||||
|
int offset_row = (c256_region.origin.y + y) * c256_max_size.width;
|
||||||
|
for (x = 0; x < c256_region.size.width; x++) {
|
||||||
|
int offset = offset_row + c256_region.origin.x + x;
|
||||||
|
tvky_text_matrix[offset] = c;
|
||||||
|
tvky_color_matrix[offset] = c256_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the position of the cursor to (x, y) relative to the current region
|
||||||
|
* If the (x, y) coordinate is outside the region, it will be clipped to the region.
|
||||||
|
* If y is greater than the height of the region, the region will scroll until that relative
|
||||||
|
* position would be within view.
|
||||||
|
*
|
||||||
|
* @param x the column for the cursor
|
||||||
|
* @param y the row for the cursor
|
||||||
|
*/
|
||||||
|
static void txt_c256_set_xy(short x, short y) {
|
||||||
|
/* Make sure X is within range for the current region... "print" a newline if not */
|
||||||
|
if (x < 0) {
|
||||||
|
x = 0;
|
||||||
|
} else if (x >= c256_region.size.width) {
|
||||||
|
x = 0;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure Y is within range for the current region... scroll if not */
|
||||||
|
if (y < 0) {
|
||||||
|
y = 0;
|
||||||
|
} else if (y >= c256_region.size.height) {
|
||||||
|
txt_c256_scroll(0, y - c256_region.size.height + 1);
|
||||||
|
y = c256_region.size.height - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
c256_cursor.x = x;
|
||||||
|
c256_cursor.y = y;
|
||||||
|
|
||||||
|
/* Set register */
|
||||||
|
tvky_crsr_ctrl->column = c256_region.origin.x + x;
|
||||||
|
tvky_crsr_ctrl->row = c256_region.origin.y + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position of the cursor (x, y) relative to the current region
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param position pointer to a t_point record to fill out
|
||||||
|
*/
|
||||||
|
static void txt_c256_get_xy(p_point position) {
|
||||||
|
position->x = c256_cursor.x;
|
||||||
|
position->y = c256_cursor.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a character to the current cursor position in the current color
|
||||||
|
*
|
||||||
|
* @param c the character to print
|
||||||
|
*/
|
||||||
|
static void txt_c256_put(char c) {
|
||||||
|
short x;
|
||||||
|
short y;
|
||||||
|
unsigned int offset;
|
||||||
|
|
||||||
|
x = c256_region.origin.x + c256_cursor.x;
|
||||||
|
y = c256_region.origin.y + c256_cursor.y;
|
||||||
|
offset = y * c256_max_size.width + x;
|
||||||
|
tvky_text_matrix[offset] = c;
|
||||||
|
tvky_color_matrix[offset] = c256_color;
|
||||||
|
|
||||||
|
txt_c256_set_xy(c256_cursor.x + 1, c256_cursor.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the screen
|
||||||
|
*/
|
||||||
|
static void txt_c256_init() {
|
||||||
|
char buffer[255];
|
||||||
|
t_rect region;
|
||||||
|
int i;
|
||||||
|
DEBUG("txt_c256_init");
|
||||||
|
|
||||||
|
c256_resolution.width = 0;
|
||||||
|
c256_resolution.height = 0;
|
||||||
|
c256_visible_size.width = 0;
|
||||||
|
c256_visible_size.height = 0;
|
||||||
|
c256_font_size.width = 0;
|
||||||
|
c256_font_size.height = 0;
|
||||||
|
|
||||||
|
/* Disable the set_sizes call for now, to avoid computing transcient unnecessary values */
|
||||||
|
c256_enable_set_sizes = 0;
|
||||||
|
|
||||||
|
/* Start with nothing on */
|
||||||
|
msr_shadow = 0;
|
||||||
|
|
||||||
|
/* Define the capabilities */
|
||||||
|
|
||||||
|
/* Specify the screen number. We have only one so... */
|
||||||
|
c256_caps.number = TXT_SCREEN_C256;
|
||||||
|
|
||||||
|
/* This screen can be text, bitmap or can be put to sleep */
|
||||||
|
c256_caps.supported_modes = TXT_MODE_TEXT | TXT_MODE_SPRITE | TXT_MODE_BITMAP | TXT_MODE_TILE | TXT_MODE_SLEEP;
|
||||||
|
|
||||||
|
/* Supported resolutions */
|
||||||
|
c256_caps.resolution_count = sizeof(c256_resolutions) / sizeof(t_extent);
|
||||||
|
c256_caps.resolutions = c256_resolutions;
|
||||||
|
|
||||||
|
/* Only 8x8 on the U */
|
||||||
|
c256_caps.font_size_count = sizeof(c256_fonts) / sizeof(t_extent);
|
||||||
|
c256_caps.font_sizes = c256_fonts;
|
||||||
|
|
||||||
|
/* Initialize the color lookup tables */
|
||||||
|
for (i = 0; i < sizeof(c256_clut)/sizeof(t_color4); i++) {
|
||||||
|
tvky_text_fg_color[i] = c256_clut[i];
|
||||||
|
tvky_text_bg_color[i] = c256_clut[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the mode to text */
|
||||||
|
txt_c256_set_mode(TXT_MODE_TEXT);
|
||||||
|
|
||||||
|
/* Set the resolution */
|
||||||
|
txt_c256_set_resolution(640, 480);
|
||||||
|
|
||||||
|
/* Set the default color: light grey on blue */
|
||||||
|
txt_c256_set_color(0x07, 0x04);
|
||||||
|
|
||||||
|
/* Set the font */
|
||||||
|
txt_c256_set_font(8, 8, MSX_CP437_8x8_bin); /* Use 8x8 font */
|
||||||
|
|
||||||
|
/* Set the cursor */
|
||||||
|
txt_c256_set_cursor(1, 0, 0xB1);
|
||||||
|
|
||||||
|
/* Set the border */
|
||||||
|
txt_c256_set_border(0, 0); /* Set up the border */
|
||||||
|
txt_c256_set_border_color(0, 0, 0x3f);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable set_sizes, now that everything is set up initially
|
||||||
|
* And calculate the size of the screen
|
||||||
|
*/
|
||||||
|
c256_enable_set_sizes = 1;
|
||||||
|
txt_c256_set_sizes();
|
||||||
|
|
||||||
|
/* Set region to default */
|
||||||
|
region.origin.x = 0;
|
||||||
|
region.origin.y = 0;
|
||||||
|
region.size.width = 0;
|
||||||
|
region.size.height = 0;
|
||||||
|
txt_c256_set_region(®ion);
|
||||||
|
|
||||||
|
/* Home the cursor */
|
||||||
|
txt_c256_set_xy(0, 0);
|
||||||
|
|
||||||
|
/* Clear the screen */
|
||||||
|
txt_c256_fill(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize and install the driver
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
short txt_c256_install() {
|
||||||
|
t_txt_device device;
|
||||||
|
|
||||||
|
device.number = TXT_SCREEN_C256;
|
||||||
|
device.name = "SCREEN";
|
||||||
|
|
||||||
|
device.init = txt_c256_init;
|
||||||
|
device.get_capabilities = txt_c256_get_capabilities;
|
||||||
|
device.set_mode = txt_c256_set_mode;
|
||||||
|
device.set_sizes = txt_c256_set_sizes;
|
||||||
|
device.set_resolution = txt_c256_set_resolution;
|
||||||
|
device.set_border = txt_c256_set_border;
|
||||||
|
device.set_border_color = txt_c256_set_border_color;
|
||||||
|
device.set_font = txt_c256_set_font;
|
||||||
|
device.set_cursor = txt_c256_set_cursor;
|
||||||
|
device.set_cursor_visible = txt_c256_set_cursor_visible;
|
||||||
|
device.get_region = txt_c256_get_region;
|
||||||
|
device.set_region = txt_c256_set_region;
|
||||||
|
device.get_color = txt_c256_get_color;
|
||||||
|
device.set_color = txt_c256_set_color;
|
||||||
|
device.set_xy = txt_c256_set_xy;
|
||||||
|
device.get_xy = txt_c256_get_xy;
|
||||||
|
device.put = txt_c256_put;
|
||||||
|
device.scroll = txt_c256_scroll;
|
||||||
|
device.fill = txt_c256_fill;
|
||||||
|
device.get_sizes = txt_c256_get_sizes;
|
||||||
|
|
||||||
|
return txt_register(&device);
|
||||||
|
}
|
19
src/dev/txt_c256.h
Normal file
19
src/dev/txt_c256.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/** @file txt_c2560.h
|
||||||
|
*
|
||||||
|
* Text screen driver for the C256
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TXT_C256_H
|
||||||
|
#define __TXT_C256_H
|
||||||
|
|
||||||
|
/* We only have one screen */
|
||||||
|
#define TXT_SCREEN_C256 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize and install the driver
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
extern short txt_c256_install();
|
||||||
|
|
||||||
|
#endif
|
709
src/dev/txt_evid.c
Normal file
709
src/dev/txt_evid.c
Normal file
|
@ -0,0 +1,709 @@
|
||||||
|
/**
|
||||||
|
* @file txt_evid.c
|
||||||
|
* @brief Low level FoenixMCP driver for the C200 EVID expansion card for the C256 computers
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-08-09
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "C256/exp_c256.h"
|
||||||
|
#include "C256/vicky_ii.h"
|
||||||
|
#include "dev/txt_evid.h"
|
||||||
|
#include "dev/txt_screen.h"
|
||||||
|
|
||||||
|
#define evid_font_set ((volatile __attribute__((far)) uint8_t *)0xae1000)
|
||||||
|
#define evid_fg_clut ((volatile __attribute__((far)) t_color4 *)0xae1b00)
|
||||||
|
#define evid_bg_clut ((volatile __attribute__((far)) t_color4 *)0xae1b40)
|
||||||
|
|
||||||
|
#define evid_mstr_ctrl ((volatile __attribute__((far)) uint16_t *)0xae1e00)
|
||||||
|
#define EVID_MCR_TEXT 0x0001
|
||||||
|
#define EVID_MCR_RES_800x600 0x0100
|
||||||
|
|
||||||
|
#define evid_brdr_ctrl ((volatile __attribute__((far)) uint8_t *)0xae1e04)
|
||||||
|
#define evid_brdr_color ((volatile __attribute__((far)) t_color4 *)0xae1e05)
|
||||||
|
#define evid_brdr_size_x ((volatile __attribute__((far)) uint16_t *)0xae1e08)
|
||||||
|
#define evid_brdr_size_y ((volatile __attribute__((far)) uint16_t *)0xae1e09)
|
||||||
|
|
||||||
|
#define evid_crsr_ctrl ((volatile __attribute__((far)) uint8_t *)0xae1e10)
|
||||||
|
#define evid_crsr_char ((volatile __attribute__((far)) uint8_t *)0xae1e12)
|
||||||
|
#define evid_crsr_color ((volatile __attribute__((far)) uint8_t *)0xae1e13)
|
||||||
|
#define evid_crsr_column ((volatile __attribute__((far)) uint16_t *)0xae1e14)
|
||||||
|
#define evid_crsr_row ((volatile __attribute__((far)) uint16_t *)0xae1e16)
|
||||||
|
|
||||||
|
#define evid_text_matrix ((volatile __attribute__((far)) uint8_t *)0xae2000)
|
||||||
|
#define evid_color_matrix ((volatile __attribute__((far)) uint8_t *)0xae4000)
|
||||||
|
|
||||||
|
extern const unsigned char MSX_CP437_8x8_bin[];
|
||||||
|
|
||||||
|
const t_color4 evid_clut[] = {
|
||||||
|
{0, 0, 0}, // 0: Black
|
||||||
|
{0, 0, 128}, // 1: Red
|
||||||
|
{0, 128, 0}, // 2: Green
|
||||||
|
{0, 128, 128}, // 3: Yellow
|
||||||
|
{128, 0, 0}, // 4: Blue
|
||||||
|
{128, 0, 128}, // 5: Magenta
|
||||||
|
{128, 128, 0}, // 6: Cyan
|
||||||
|
{192, 192, 192}, // 7: White
|
||||||
|
{128, 128, 128}, // 8: Bright Gray
|
||||||
|
{0, 0, 255}, // 9: Bright Red
|
||||||
|
{0, 255, 0}, // A: Bright Green
|
||||||
|
{0, 255, 255}, // B: Bright Yellow
|
||||||
|
{255, 0, 0}, // C: Bright Blue
|
||||||
|
{255, 0, 255}, // D: Bright Magenta
|
||||||
|
{255, 255, 0}, // E: Bright Cyan
|
||||||
|
{255, 255, 255} // F: Bright White
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Driver level variables for the screen
|
||||||
|
*/
|
||||||
|
|
||||||
|
unsigned char evid_enable_set_sizes; /* Flag to enable set_sizes to actually do its computation */
|
||||||
|
|
||||||
|
t_txt_capabilities evid_caps; /* The capabilities of the EVID */
|
||||||
|
|
||||||
|
t_extent evid_resolutions[] = { /* The list of display resolutions */
|
||||||
|
{ 800, 600 },
|
||||||
|
{ 640, 480 }
|
||||||
|
};
|
||||||
|
|
||||||
|
t_extent evid_fonts[] = { /* The list of supported font resolutions */
|
||||||
|
{ 8, 8 }
|
||||||
|
};
|
||||||
|
|
||||||
|
t_rect evid_region; /* The current region */
|
||||||
|
t_point evid_cursor; /* The current cursor position */
|
||||||
|
t_extent evid_resolution; /* The current display resolution */
|
||||||
|
t_extent evid_font_size; /* The current font size */
|
||||||
|
t_extent evid_max_size; /* The size of the screen in characters (without border removed) */
|
||||||
|
t_extent evid_visible_size; /* The size of the visible screen in characters (with border removed) */
|
||||||
|
short evid_border_width; /* Width of the border on one side */
|
||||||
|
short evid_border_height; /* Height of the border on one side */
|
||||||
|
unsigned char evid_color; /* The current color */
|
||||||
|
unsigned long evid_msr_shadow; /* A shadow register for the Master Control Register */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return TRUE if the C200 EVID card is present
|
||||||
|
*
|
||||||
|
* @return short 0 if not present, any other value means the card is present
|
||||||
|
*/
|
||||||
|
short txt_evid_present() {
|
||||||
|
if ((EXP_CARD_INFO->vendor_id == EXP_VENDOR_FOENIX) && (EXP_CARD_INFO->card_id == EXP_CARD_C200_EVID)) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the description of a screen's capabilities
|
||||||
|
*
|
||||||
|
* @return a pointer to the read-only description (0 on error)
|
||||||
|
*/
|
||||||
|
const p_txt_capabilities txt_evid_get_capabilities() {
|
||||||
|
return &evid_caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the size of the text screen in rows and columns so that
|
||||||
|
* the kernel printing routines can work correctly.
|
||||||
|
*
|
||||||
|
* NOTE: this should be called whenever the VKY3 registers are changed
|
||||||
|
*/
|
||||||
|
static void txt_evid_set_sizes() {
|
||||||
|
TRACE("txt_evid_set_sizes");
|
||||||
|
|
||||||
|
if (evid_enable_set_sizes) {
|
||||||
|
/* Only recalculate after initialization is mostly completed */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the maximum number of characters visible on the screen
|
||||||
|
* This controls text layout in memory
|
||||||
|
*/
|
||||||
|
evid_max_size.width = evid_resolution.width / evid_font_size.width;
|
||||||
|
evid_max_size.height = evid_resolution.height / evid_font_size.height;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the characters that are visible in whole or in part
|
||||||
|
*/
|
||||||
|
if ((evid_border_width != 0) && (evid_border_height != 0)) {
|
||||||
|
short border_width = (2 * evid_border_width) / evid_font_size.width;
|
||||||
|
short border_height = (2 * evid_border_height) / evid_font_size.height;
|
||||||
|
|
||||||
|
evid_visible_size.width = evid_max_size.width - border_width;
|
||||||
|
evid_visible_size.height = evid_max_size.height - border_height;
|
||||||
|
} else {
|
||||||
|
evid_visible_size.width = evid_max_size.width;
|
||||||
|
evid_visible_size.height = evid_max_size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG4("txt_evid_set_sizes max:%d,%d, visible:%d,%d", evid_max_size.width, evid_max_size.height, evid_visible_size.width, evid_visible_size.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the display resolutions
|
||||||
|
*
|
||||||
|
* @param text_size the size of the screen in visible characters (may be null)
|
||||||
|
* @param pixel_size the size of the screen in pixels (may be null)
|
||||||
|
*/
|
||||||
|
static void txt_evid_get_sizes(p_extent text_size, p_extent pixel_size) {
|
||||||
|
if (text_size) {
|
||||||
|
text_size->width = evid_visible_size.width;
|
||||||
|
text_size->height = evid_visible_size.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixel_size) {
|
||||||
|
pixel_size->width = evid_resolution.width;
|
||||||
|
pixel_size->height = evid_resolution.height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the display mode for the screen
|
||||||
|
*
|
||||||
|
* @param mode a bitfield of desired display mode options
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the mode is invalid for the screen
|
||||||
|
*/
|
||||||
|
static short txt_evid_set_mode(short mode) {
|
||||||
|
/* Turn off anything not set */
|
||||||
|
evid_msr_shadow &= ~(TXT_MODE_TEXT);
|
||||||
|
|
||||||
|
if (mode & TXT_MODE_TEXT) {
|
||||||
|
/* Put on text mode */
|
||||||
|
evid_msr_shadow |= EVID_MCR_TEXT;
|
||||||
|
*evid_mstr_ctrl = evid_msr_shadow;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Unsupported mode */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the display resolution of the screen
|
||||||
|
*
|
||||||
|
* @param width the desired horizontal resolution in pixels
|
||||||
|
* @param height the desired veritical resolution in pixels
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the resolution is unsupported
|
||||||
|
*/
|
||||||
|
static short txt_evid_set_resolution(short width, short height) {
|
||||||
|
// TODO: If no size specified, set it based on the DIP switch
|
||||||
|
|
||||||
|
/* Turn off resolution bits */
|
||||||
|
/* TODO: there gotta be a better way to do that */
|
||||||
|
evid_msr_shadow &= ~(EVID_MCR_RES_800x600);
|
||||||
|
|
||||||
|
if ((width == 800) && (height == 600)) {
|
||||||
|
evid_msr_shadow |= EVID_MCR_RES_800x600;
|
||||||
|
evid_resolution.width = width;
|
||||||
|
evid_resolution.height = height;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_evid_set_sizes();
|
||||||
|
|
||||||
|
*evid_mstr_ctrl = evid_msr_shadow;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else if ((width == 640) && (height == 480)) {
|
||||||
|
evid_resolution.width = width;
|
||||||
|
evid_resolution.height = height;
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_evid_set_sizes();
|
||||||
|
|
||||||
|
*evid_mstr_ctrl = evid_msr_shadow;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Unsupported resolution */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the border of the screen (if supported)
|
||||||
|
*
|
||||||
|
* @param width the horizontal size of one side of the border (0 - 32 pixels)
|
||||||
|
* @param height the vertical size of one side of the border (0 - 32 pixels)
|
||||||
|
*/
|
||||||
|
static void txt_evid_set_border(short width, short height) {
|
||||||
|
if ((width > 0) || (height > 0)) {
|
||||||
|
evid_border_width = width;
|
||||||
|
evid_border_height = height;
|
||||||
|
*evid_brdr_ctrl = 0x01;
|
||||||
|
*evid_brdr_size_x = width;
|
||||||
|
*evid_brdr_size_y = height;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
*evid_brdr_ctrl = 0;
|
||||||
|
*evid_brdr_size_x = 0;
|
||||||
|
*evid_brdr_size_y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_evid_set_sizes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the border of the screen (if supported)
|
||||||
|
*
|
||||||
|
* @param red the red component of the color (0 - 255)
|
||||||
|
* @param green the green component of the color (0 - 255)
|
||||||
|
* @param blue the blue component of the color (0 - 255)
|
||||||
|
*/
|
||||||
|
static void txt_evid_set_border_color(unsigned char red, unsigned char green, unsigned char blue) {
|
||||||
|
evid_brdr_color->red = red;
|
||||||
|
evid_brdr_color->green = green;
|
||||||
|
evid_brdr_color->blue = blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a font as the current font for the screen
|
||||||
|
*
|
||||||
|
* @param width width of a character in pixels
|
||||||
|
* @param height of a character in pixels
|
||||||
|
* @param data pointer to the raw font data to be loaded
|
||||||
|
*/
|
||||||
|
static short txt_evid_set_font(short width, short height, const unsigned char * data) {
|
||||||
|
if (width == 8 && height == 8) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* The size is valid... set the font */
|
||||||
|
evid_font_size.width = width;
|
||||||
|
evid_font_size.height = height;
|
||||||
|
|
||||||
|
/* Copy the font data... this assumes a width of one byte! */
|
||||||
|
/* TODO: generalize this for all possible font sizes */
|
||||||
|
for (i = 0; i < 256 * height; i++) {
|
||||||
|
evid_font_set[i] = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalculate the size of the screen
|
||||||
|
txt_evid_set_sizes();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the appearance of the cursor
|
||||||
|
*
|
||||||
|
* @param enable 0 to hide, any other number to make visible
|
||||||
|
* @param rate the blink rate for the cursor (0=1s, 1=0.5s, 2=0.25s, 3=1/5s)
|
||||||
|
* @param c the character in the current font to use as a cursor
|
||||||
|
*/
|
||||||
|
static void txt_evid_set_cursor(short enable, short rate, char c) {
|
||||||
|
*evid_crsr_ctrl = ((rate & 0x03) << 1) | ((enable) ? 1 : 0);
|
||||||
|
*evid_crsr_char = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set if the cursor is visible or not
|
||||||
|
*
|
||||||
|
* @param enable 0 to hide, any other number to make visible
|
||||||
|
*/
|
||||||
|
static void txt_evid_set_cursor_visible(short enable) {
|
||||||
|
if (enable) {
|
||||||
|
*evid_crsr_ctrl|= 0x01;
|
||||||
|
} else {
|
||||||
|
*evid_crsr_ctrl &= ~0x01;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the current region
|
||||||
|
*
|
||||||
|
* @param region pointer to a t_rect describing the rectangular region (using character cells for size and size)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the region was invalid
|
||||||
|
*/
|
||||||
|
static short txt_evid_get_region(p_rect region) {
|
||||||
|
region->origin.x = evid_region.origin.x;
|
||||||
|
region->origin.y = evid_region.origin.y;
|
||||||
|
region->size.width = evid_region.size.width;
|
||||||
|
region->size.height = evid_region.size.height;
|
||||||
|
|
||||||
|
// {
|
||||||
|
// char msg[80];
|
||||||
|
// sprintf(msg,"txt_evid_get_region %p: x:%d, y:%d, w:%d, h:%d", region, region->origin.x, region->origin.y, region->size.width, region->size.height);
|
||||||
|
// DEBUG(msg);
|
||||||
|
// }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a region to restrict further character display, scrolling, etc.
|
||||||
|
* Note that a region of zero size will reset the region to the full size of the screen.
|
||||||
|
*
|
||||||
|
* @param region pointer to a t_rect describing the rectangular region (using character cells for size and size)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the region was invalid
|
||||||
|
*/
|
||||||
|
static short txt_evid_set_region(const p_rect region) {
|
||||||
|
// char msg[80];
|
||||||
|
// sprintf(msg,"SET REGION %p x:%d, y:%d, w:%d, h:%d (visible:%d,%d)",
|
||||||
|
// region, region->origin.x, region->origin.y, region->size.width, region->size.height, evid_visible_size.width, evid_visible_size.height);
|
||||||
|
// DEBUG(msg);
|
||||||
|
|
||||||
|
if ((region->size.width == 0) || (region->size.height == 0)) {
|
||||||
|
/* Set the region to the default (full screen) */
|
||||||
|
evid_region.origin.x = 0;
|
||||||
|
evid_region.origin.y = 0;
|
||||||
|
evid_region.size.width = evid_visible_size.width;
|
||||||
|
evid_region.size.height = evid_visible_size.height;
|
||||||
|
} else {
|
||||||
|
evid_region.origin.x = region->origin.x;
|
||||||
|
evid_region.origin.y = region->origin.y;
|
||||||
|
evid_region.size.width = region->size.width;
|
||||||
|
evid_region.size.height = region->size.height;
|
||||||
|
|
||||||
|
//sprintf(msg,"specific region %d %d %d %d", region->origin.x, region->origin.y, region->size.width, region->size.height);
|
||||||
|
//DEBUG(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
//sprintf(msg,"txt_evid_set_region: NEW REGION %p x:%d, y:%d, w:%d, h:%d (visible:%d,%d)",
|
||||||
|
//region, region->origin.x, region->origin.y, region->size.width, region->size.height, evid_visible_size.width, evid_visible_size.height);
|
||||||
|
//DEBUG(msg);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default foreground and background colors for printing
|
||||||
|
*
|
||||||
|
* @param pointer to the foreground the Text LUT index of the new current foreground color (0 - 15)
|
||||||
|
* @param pointer to the background the Text LUT index of the new current background color (0 - 15)
|
||||||
|
*/
|
||||||
|
static short txt_evid_get_color(unsigned char * foreground, unsigned char * background) {
|
||||||
|
*foreground = (evid_color & 0xf0) >> 4;
|
||||||
|
*background = evid_color & 0x0f;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default foreground and background colors for printing
|
||||||
|
*
|
||||||
|
* @param foreground the Text LUT index of the new current foreground color (0 - 15)
|
||||||
|
* @param background the Text LUT index of the new current background color (0 - 15)
|
||||||
|
*/
|
||||||
|
static short txt_evid_set_color(unsigned char foreground, unsigned char background) {
|
||||||
|
evid_color = ((foreground & 0x0f) << 4) + (background & 0x0f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll the text in the current region
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param horizontal the number of columns to scroll (negative is left, positive is right)
|
||||||
|
* @param vertical the number of rows to scroll (negative is down, positive is up)
|
||||||
|
*/
|
||||||
|
static void txt_evid_scroll(short horizontal, short vertical) {
|
||||||
|
short x, x0, x1, x2, x3, dx;
|
||||||
|
short y, y0, y1, y2, y3, dy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine limits of rectangles to move and fill and directions of loops
|
||||||
|
* x0 and y0 are the positions of the first cell to be over-written
|
||||||
|
* x1 and y1 are the positions of the first cell to be copied... TEXT[x0,y0] := TEXT[x1,y1]
|
||||||
|
* x2 and y2 are the position of the last cell to be over-written
|
||||||
|
* x3 and y3 are the position of the last cell to be copied... TEXT[x2,y2] := TEXT[x3,y3]
|
||||||
|
*
|
||||||
|
* When blanking, the rectangles (x2,y0) - (x3,y3) and (x0,y2) - (x2,y3) are cleared
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Determine the row limits
|
||||||
|
|
||||||
|
if (vertical >= 0) {
|
||||||
|
y0 = evid_region.origin.y;
|
||||||
|
y1 = y0 + vertical;
|
||||||
|
y3 = evid_region.origin.y + evid_region.size.height;
|
||||||
|
y2 = y3 - vertical;
|
||||||
|
dy = 1;
|
||||||
|
} else {
|
||||||
|
y0 = evid_region.origin.y + evid_region.size.height - 1;
|
||||||
|
y1 = y0 + vertical;
|
||||||
|
y3 = evid_region.origin.y - 1;
|
||||||
|
y2 = y3 - vertical;
|
||||||
|
dy = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the column limits
|
||||||
|
|
||||||
|
if (horizontal >= 0) {
|
||||||
|
x0 = evid_region.origin.x;
|
||||||
|
x1 = x0 + horizontal;
|
||||||
|
x3 = evid_region.origin.x + evid_region.size.width;
|
||||||
|
x2 = x3 - horizontal;
|
||||||
|
dx = 1;
|
||||||
|
} else {
|
||||||
|
x0 = evid_region.origin.x + evid_region.size.width - 1;
|
||||||
|
x1 = x0 + horizontal;
|
||||||
|
x3 = evid_region.origin.x - 1;
|
||||||
|
x2 = x3 - horizontal;
|
||||||
|
dx = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the rectangle. */
|
||||||
|
int delta_y = dy * evid_max_size.width;
|
||||||
|
int row_dst = y0 * evid_max_size.width - delta_y;
|
||||||
|
int row_src = y0 * evid_max_size.width + vertical * evid_max_size.width - delta_y;
|
||||||
|
for (y = y0; y != y2; y += dy) {
|
||||||
|
row_dst += delta_y;
|
||||||
|
row_src += delta_y;
|
||||||
|
int offset_dst = row_dst + x0 - dx;
|
||||||
|
int offset_src = row_src + horizontal + x0 - dx;
|
||||||
|
for (x = x0; x != x2; x += dx) {
|
||||||
|
offset_dst += dx;
|
||||||
|
offset_src += dx;
|
||||||
|
evid_text_matrix[offset_dst] = evid_text_matrix[offset_src];
|
||||||
|
evid_color_matrix[offset_dst] = evid_color_matrix[offset_src];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the rectangles */
|
||||||
|
if (horizontal != 0) {
|
||||||
|
row_dst = y0 * evid_max_size.width - delta_y;
|
||||||
|
for (y = y0; y != y3; y += dy) {
|
||||||
|
row_dst += delta_y;
|
||||||
|
for (x = x2; x != x3; x += dx) {
|
||||||
|
evid_text_matrix[row_dst + x] = ' ';
|
||||||
|
evid_color_matrix[row_dst + x] = evid_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertical != 0) {
|
||||||
|
row_dst = y2 * evid_max_size.width - delta_y;
|
||||||
|
for (y = y2; y != y3; y += dy) {
|
||||||
|
row_dst += delta_y;
|
||||||
|
for (x = x0; x != x3; x += dx) {
|
||||||
|
evid_text_matrix[row_dst + x] = ' ';
|
||||||
|
evid_color_matrix[row_dst + x] = evid_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the current region with a character in the current color
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param c the character to fill the region with
|
||||||
|
*/
|
||||||
|
static void txt_evid_fill(char c) {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
|
||||||
|
for (y = 0; y < evid_region.size.height; y++) {
|
||||||
|
int offset_row = (evid_region.origin.y + y) * evid_max_size.width;
|
||||||
|
for (x = 0; x < evid_region.size.width; x++) {
|
||||||
|
int offset = offset_row + evid_region.origin.x + x;
|
||||||
|
evid_text_matrix[offset] = c;
|
||||||
|
evid_color_matrix[offset] = evid_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the position of the cursor to (x, y) relative to the current region
|
||||||
|
* If the (x, y) coordinate is outside the region, it will be clipped to the region.
|
||||||
|
* If y is greater than the height of the region, the region will scroll until that relative
|
||||||
|
* position would be within view.
|
||||||
|
*
|
||||||
|
* @param x the column for the cursor
|
||||||
|
* @param y the row for the cursor
|
||||||
|
*/
|
||||||
|
static void txt_evid_set_xy(short x, short y) {
|
||||||
|
/* Make sure X is within range for the current region... "print" a newline if not */
|
||||||
|
if (x < 0) {
|
||||||
|
x = 0;
|
||||||
|
} else if (x >= evid_region.size.width) {
|
||||||
|
x = 0;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure Y is within range for the current region... scroll if not */
|
||||||
|
if (y < 0) {
|
||||||
|
y = 0;
|
||||||
|
} else if (y >= evid_region.size.height) {
|
||||||
|
txt_evid_scroll(0, y - evid_region.size.height + 1);
|
||||||
|
y = evid_region.size.height - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
evid_cursor.x = x;
|
||||||
|
evid_cursor.y = y;
|
||||||
|
|
||||||
|
/* Set register */
|
||||||
|
*evid_crsr_column = evid_region.origin.x + x;
|
||||||
|
*evid_crsr_row = evid_region.origin.y + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position of the cursor (x, y) relative to the current region
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param position pointer to a t_point record to fill out
|
||||||
|
*/
|
||||||
|
static void txt_evid_get_xy(p_point position) {
|
||||||
|
position->x = evid_cursor.x;
|
||||||
|
position->y = evid_cursor.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a character to the current cursor position in the current color
|
||||||
|
*
|
||||||
|
* @param c the character to print
|
||||||
|
*/
|
||||||
|
static void txt_evid_put(char c) {
|
||||||
|
short x;
|
||||||
|
short y;
|
||||||
|
unsigned int offset;
|
||||||
|
|
||||||
|
x = evid_region.origin.x + evid_cursor.x;
|
||||||
|
y = evid_region.origin.y + evid_cursor.y;
|
||||||
|
offset = y * evid_max_size.width + x;
|
||||||
|
evid_text_matrix[offset] = c;
|
||||||
|
evid_color_matrix[offset] = evid_color;
|
||||||
|
|
||||||
|
txt_evid_set_xy(evid_cursor.x + 1, evid_cursor.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the screen
|
||||||
|
*/
|
||||||
|
static void txt_evid_init() {
|
||||||
|
char buffer[255];
|
||||||
|
t_rect region;
|
||||||
|
int i;
|
||||||
|
DEBUG("txt_evid_init");
|
||||||
|
|
||||||
|
evid_resolution.width = 0;
|
||||||
|
evid_resolution.height = 0;
|
||||||
|
evid_visible_size.width = 0;
|
||||||
|
evid_visible_size.height = 0;
|
||||||
|
evid_font_size.width = 0;
|
||||||
|
evid_font_size.height = 0;
|
||||||
|
|
||||||
|
/* Disable the set_sizes call for now, to avoid computing transcient unnecessary values */
|
||||||
|
evid_enable_set_sizes = 0;
|
||||||
|
|
||||||
|
/* Start with nothing on */
|
||||||
|
evid_msr_shadow = 0;
|
||||||
|
|
||||||
|
/* Define the capabilities */
|
||||||
|
|
||||||
|
/* Specify the screen number. We have only one so... */
|
||||||
|
evid_caps.number = TXT_SCREEN_EVID;
|
||||||
|
|
||||||
|
/* This screen can be text, bitmap or can be put to sleep */
|
||||||
|
evid_caps.supported_modes = TXT_MODE_TEXT;
|
||||||
|
|
||||||
|
/* Supported resolutions */
|
||||||
|
evid_caps.resolution_count = sizeof(evid_resolutions) / sizeof(t_extent);
|
||||||
|
evid_caps.resolutions = evid_resolutions;
|
||||||
|
|
||||||
|
/* Only 8x8 on the U */
|
||||||
|
evid_caps.font_size_count = sizeof(evid_fonts) / sizeof(t_extent);
|
||||||
|
evid_caps.font_sizes = evid_fonts;
|
||||||
|
|
||||||
|
/* Initialize the color lookup tables */
|
||||||
|
for (i = 0; i < sizeof(evid_clut)/sizeof(t_color4); i++) {
|
||||||
|
evid_fg_clut[i] = evid_clut[i];
|
||||||
|
evid_bg_clut[i] = evid_clut[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the mode to text */
|
||||||
|
txt_evid_set_mode(TXT_MODE_TEXT);
|
||||||
|
|
||||||
|
/* Set the resolution */
|
||||||
|
txt_evid_set_resolution(640, 480);
|
||||||
|
|
||||||
|
/* Set the default color: light grey on blue */
|
||||||
|
txt_evid_set_color(0x07, 0x04);
|
||||||
|
|
||||||
|
/* Set the font */
|
||||||
|
txt_evid_set_font(8, 8, MSX_CP437_8x8_bin); /* Use 8x8 font */
|
||||||
|
|
||||||
|
/* Set the cursor */
|
||||||
|
txt_evid_set_cursor(1, 0, 0xB1);
|
||||||
|
|
||||||
|
/* Set the border */
|
||||||
|
txt_evid_set_border(16, 16); /* Set up the border */
|
||||||
|
txt_evid_set_border_color(0, 0, 0x3f);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable set_sizes, now that everything is set up initially
|
||||||
|
* And calculate the size of the screen
|
||||||
|
*/
|
||||||
|
evid_enable_set_sizes = 1;
|
||||||
|
txt_evid_set_sizes();
|
||||||
|
|
||||||
|
/* Set region to default */
|
||||||
|
region.origin.x = 0;
|
||||||
|
region.origin.y = 0;
|
||||||
|
region.size.width = 0;
|
||||||
|
region.size.height = 0;
|
||||||
|
txt_evid_set_region(®ion);
|
||||||
|
|
||||||
|
/* Home the cursor */
|
||||||
|
txt_evid_set_xy(0, 0);
|
||||||
|
|
||||||
|
/* Clear the screen */
|
||||||
|
txt_evid_fill(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
t_txt_device device;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize and install the driver
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
short txt_evid_install() {
|
||||||
|
if (txt_evid_present()) {
|
||||||
|
// Only register the EVID driver if the EVID is installed
|
||||||
|
|
||||||
|
device.number = TXT_SCREEN_EVID;
|
||||||
|
device.name = "EVID";
|
||||||
|
|
||||||
|
device.init = txt_evid_init;
|
||||||
|
device.get_capabilities = txt_evid_get_capabilities;
|
||||||
|
device.set_mode = txt_evid_set_mode;
|
||||||
|
device.set_sizes = txt_evid_set_sizes;
|
||||||
|
device.set_resolution = txt_evid_set_resolution;
|
||||||
|
device.set_border = txt_evid_set_border;
|
||||||
|
device.set_border_color = txt_evid_set_border_color;
|
||||||
|
device.set_font = txt_evid_set_font;
|
||||||
|
device.set_cursor = txt_evid_set_cursor;
|
||||||
|
device.set_cursor_visible = txt_evid_set_cursor_visible;
|
||||||
|
device.get_region = txt_evid_get_region;
|
||||||
|
device.set_region = txt_evid_set_region;
|
||||||
|
device.get_color = txt_evid_get_color;
|
||||||
|
device.set_color = txt_evid_set_color;
|
||||||
|
device.set_xy = txt_evid_set_xy;
|
||||||
|
device.get_xy = txt_evid_get_xy;
|
||||||
|
device.put = txt_evid_put;
|
||||||
|
device.scroll = txt_evid_scroll;
|
||||||
|
device.fill = txt_evid_fill;
|
||||||
|
device.get_sizes = txt_evid_get_sizes;
|
||||||
|
|
||||||
|
return txt_register(&device);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Return an error if the EVID is not present
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
22
src/dev/txt_evid.h
Normal file
22
src/dev/txt_evid.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/**
|
||||||
|
* @file txt_evid.c
|
||||||
|
* @brief Low level FoenixMCP driver for the C200 EVID expansion card for the C256 computers
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-08-09
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __txt_evid_h__
|
||||||
|
#define __txt_evid_h__
|
||||||
|
|
||||||
|
/* If installed, the EVID is the second screen on the C256. */
|
||||||
|
#define TXT_SCREEN_EVID 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize and install the driver
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
extern short txt_evid_install();
|
||||||
|
|
||||||
|
#endif
|
725
src/dev/txt_screen.c
Normal file
725
src/dev/txt_screen.c
Normal file
|
@ -0,0 +1,725 @@
|
||||||
|
/**
|
||||||
|
* @file txt_screen.c
|
||||||
|
*
|
||||||
|
* Uniform routines to manage the text screens
|
||||||
|
*
|
||||||
|
* The console code will call this layer, which will dispatch those calls
|
||||||
|
* to the low level drivers (e.g. txt_a2560k_a) registered with it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "log_level.h"
|
||||||
|
#ifndef DEFAULT_LOG_LEVEL
|
||||||
|
#define DEFAULT_LOG_LEVEL LOG_ERROR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "dev/txt_screen.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The array of device drivers.
|
||||||
|
*
|
||||||
|
* If the number of the driver record is 0, no driver is registered for that device
|
||||||
|
*/
|
||||||
|
static t_txt_device txt_device_driver[TXT_CNT_SCREENS];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the text system.
|
||||||
|
*/
|
||||||
|
void txt_init() {
|
||||||
|
/* Initialize all the drivers to blank... */
|
||||||
|
memset(txt_device_driver, 0, sizeof(txt_device_driver));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a device driver for a text screen
|
||||||
|
*
|
||||||
|
* The data in the provided structure will be copied to the kernel's
|
||||||
|
* internal structures. Also, the driver data provided will over-write
|
||||||
|
* any previous driver data for the device number, if one was previously
|
||||||
|
* registered.
|
||||||
|
*
|
||||||
|
* @param device the pointer to the device driver
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
short txt_register(p_txt_device device) {
|
||||||
|
DEBUG1("txt_register(%s)", device->name);
|
||||||
|
|
||||||
|
if (device->number < TXT_CNT_SCREENS) {
|
||||||
|
int i = device->number;
|
||||||
|
|
||||||
|
txt_device_driver[i].number = device->number;
|
||||||
|
txt_device_driver[i].name = device->name;
|
||||||
|
|
||||||
|
txt_device_driver[i].init = device->init;
|
||||||
|
txt_device_driver[i].get_capabilities = device->get_capabilities;
|
||||||
|
txt_device_driver[i].set_mode = device->set_mode;
|
||||||
|
txt_device_driver[i].set_sizes = device->set_sizes;
|
||||||
|
txt_device_driver[i].set_resolution = device->set_resolution;
|
||||||
|
txt_device_driver[i].set_border = device->set_border;
|
||||||
|
txt_device_driver[i].set_border_color = device->set_border_color;
|
||||||
|
txt_device_driver[i].set_font = device->set_font;
|
||||||
|
txt_device_driver[i].set_cursor = device->set_cursor;
|
||||||
|
txt_device_driver[i].set_cursor_visible = device->set_cursor_visible;
|
||||||
|
txt_device_driver[i].get_region = device->get_region;
|
||||||
|
txt_device_driver[i].set_region = device->set_region;
|
||||||
|
txt_device_driver[i].get_color = device->get_color;
|
||||||
|
txt_device_driver[i].set_color = device->set_color;
|
||||||
|
txt_device_driver[i].set_xy = device->set_xy;
|
||||||
|
txt_device_driver[i].get_xy = device->get_xy;
|
||||||
|
txt_device_driver[i].put = device->put;
|
||||||
|
txt_device_driver[i].scroll = device->scroll;
|
||||||
|
txt_device_driver[i].fill = device->fill;
|
||||||
|
txt_device_driver[i].get_sizes = device->get_sizes;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the device driver for the screen, if installed
|
||||||
|
*
|
||||||
|
* @param device the pointer to the device driver
|
||||||
|
*
|
||||||
|
* @return pointer to the device driver structure, 0 if invalid or not found
|
||||||
|
*/
|
||||||
|
p_txt_device txt_get_device(short screen) {
|
||||||
|
if (screen < TXT_CNT_SCREENS) {
|
||||||
|
p_txt_device device = &(txt_device_driver[screen]);
|
||||||
|
if (device->number == screen) {
|
||||||
|
return device;
|
||||||
|
} else {
|
||||||
|
ERROR1("txt_get_device: number mismatch %d", screen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a screen
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
*/
|
||||||
|
void txt_init_screen(short screen) {
|
||||||
|
TRACE1("txt_init_screen(%d)", (int)screen);
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->init) {
|
||||||
|
device->init();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ERROR1("Could not find screen %d", screen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the description of a screen's capabilities
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
*
|
||||||
|
* @return a pointer to the read-only description (0 on error)
|
||||||
|
*/
|
||||||
|
SYSTEMCALL const p_txt_capabilities txt_get_capabilities(short screen) {
|
||||||
|
TRACE("txt_get_capabilities");
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->get_capabilities) {
|
||||||
|
return device->get_capabilities();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the display mode for the screen
|
||||||
|
*
|
||||||
|
* @param mode a bitfield of desired display mode options
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the mode is invalid for the screen
|
||||||
|
*/
|
||||||
|
SYSTEMCALL short txt_set_mode(short screen, short mode) {
|
||||||
|
TRACE("txt_set_mode");
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->set_mode) {
|
||||||
|
return device->set_mode(mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recalculate the size of the text screen
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the mode is invalid for the screen
|
||||||
|
*/
|
||||||
|
SYSTEMCALL short txt_setsizes(short screen) {
|
||||||
|
TRACE("txt_setsizes");
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->set_sizes) {
|
||||||
|
device->set_sizes();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the display resolution of the screen
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param width the desired horizontal resolution in pixels
|
||||||
|
* @param height the desired veritical resolution in pixels
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the resolution is unsupported
|
||||||
|
*/
|
||||||
|
SYSTEMCALL short txt_set_resolution(short screen, short width, short height) {
|
||||||
|
TRACE("txt_set_resolution");
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->set_resolution) {
|
||||||
|
return device->set_resolution(width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the border of the screen (if supported)
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param width the horizontal size of one side of the border (0 - 32 pixels)
|
||||||
|
* @param height the vertical size of one side of the border (0 - 32 pixels)
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void txt_set_border(short screen, short width, short height) {
|
||||||
|
TRACE("txt_set_border");
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->set_border) {
|
||||||
|
device->set_border(width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the border of the screen (if supported)
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param red the red component of the color (0 - 255)
|
||||||
|
* @param green the green component of the color (0 - 255)
|
||||||
|
* @param blue the blue component of the color (0 - 255)
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void txt_set_border_color(short screen, unsigned char red, unsigned char green, unsigned char blue) {
|
||||||
|
TRACE("txt_set_border_color");
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->set_border_color) {
|
||||||
|
device->set_border_color(red, green, blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a font as the current font for the screen
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param width width of a character in pixels
|
||||||
|
* @param height of a character in pixels
|
||||||
|
* @param data pointer to the raw font data to be loaded
|
||||||
|
*/
|
||||||
|
SYSTEMCALL short txt_set_font(short screen, short width, short height, const unsigned char * data) {
|
||||||
|
TRACE("txt_set_font");
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->set_font) {
|
||||||
|
return device->set_font(width, height, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the appearance of the cursor
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param enable 0 to hide, any other number to make visible
|
||||||
|
* @param rate the blink rate for the cursor (0=1s, 1=0.5s, 2=0.25s, 3=1/5s)
|
||||||
|
* @param c the character in the current font to use as a cursor
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void txt_set_cursor(short screen, short enable, short rate, char c) {
|
||||||
|
TRACE("txt_set_cursor");
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->set_cursor) {
|
||||||
|
device->set_cursor(enable, rate, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the appearance of the cursor
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param enable 0 to hide, any other number to make visible
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void txt_set_cursor_visible(short screen, short enable) {
|
||||||
|
TRACE("txt_set_cursor_visible");
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->set_cursor_visible) {
|
||||||
|
device->set_cursor_visible(enable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current region.
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param region pointer to a t_rect describing the rectangular region (using character cells for size and size)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the region was invalid
|
||||||
|
*/
|
||||||
|
SYSTEMCALL short txt_get_region(short screen, p_rect region) {
|
||||||
|
DEBUG2("txt_get_region screen:%d region:%p", screen, region);
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->get_region) {
|
||||||
|
return device->get_region(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a region to restrict further character display, scrolling, etc.
|
||||||
|
* Note that a region of zero size will reset the region to the full size of the screen.
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param region pointer to a t_rect describing the rectangular region (using character cells for size and size)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the region was invalid
|
||||||
|
*/
|
||||||
|
SYSTEMCALL short txt_set_region(short screen, p_rect region) {
|
||||||
|
TRACE5("txt_set_region(%d,{x:%d; y:%d w:%d, h:%d})", (int)screen, (int)region->origin.x, (int)region->origin.y, (int)region->size.width, (int)region->size.height);
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->set_region) {
|
||||||
|
return device->set_region(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default foreground and background colors for printing
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param foreground the Text LUT index of the new current foreground color (0 - 15)
|
||||||
|
* @param background the Text LUT index of the new current background color (0 - 15)
|
||||||
|
*/
|
||||||
|
SYSTEMCALL short txt_set_color(short screen, unsigned char foreground, unsigned char background) {
|
||||||
|
TRACE3("txt_get_color(%d,%d,%d)", (int)screen, (int)foreground, (int)background);
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->set_color) {
|
||||||
|
return device->set_color(foreground, background);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the foreground and background color for printing
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* foreground = pointer to the foreground color number
|
||||||
|
* background = pointer to the background color number
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void txt_get_color(short screen, unsigned char * foreground, unsigned char * background) {
|
||||||
|
TRACE3("txt_get_color(%d,%p,%p)", (int)screen, foreground, background);
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->get_color) {
|
||||||
|
device->get_color(foreground, background);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the position of the cursor to (x, y) relative to the current region
|
||||||
|
* If the (x, y) coordinate is outside the region, it will be clipped to the region.
|
||||||
|
* If y is greater than the height of the region, the region will scroll until that relative
|
||||||
|
* position would be within view.
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param x the column for the cursor
|
||||||
|
* @param y the row for the cursor
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void txt_set_xy(short screen, short x, short y) {
|
||||||
|
DEBUG3("txt_set_xy(%d,%d,%d)", screen, (int)x, (int)y);
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->set_xy) {
|
||||||
|
device->set_xy(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position of the cursor (x, y) relative to the current region
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param position pointer to a t_point record to fill out
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void txt_get_xy(short screen, p_point position) {
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->get_xy) {
|
||||||
|
device->get_xy(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a character to the current cursor position in the current color
|
||||||
|
*
|
||||||
|
* Most character codes will result in a glyph being displayed at the current
|
||||||
|
* cursor position, advancing the cursor one spot. There are some exceptions that
|
||||||
|
* will be treated as control codes:
|
||||||
|
*
|
||||||
|
* 0x08 - BS - Move the cursor back one position, erasing the character underneath
|
||||||
|
* 0x09 - HT - Move forward to the next TAB stop
|
||||||
|
* 0x0A - LF - Move the cursor down one line (line feed)
|
||||||
|
* 0x0D - CR - Move the cursor to column 0 (carriage return)
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param c the character to print
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void txt_put(short screen, char c) {
|
||||||
|
t_point cursor;
|
||||||
|
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->put) {
|
||||||
|
switch (c) {
|
||||||
|
case CHAR_BS:
|
||||||
|
/* Backspace */
|
||||||
|
txt_get_xy(screen, &cursor);
|
||||||
|
if (cursor.x > 0) {
|
||||||
|
txt_set_xy(screen, cursor.x - 1, cursor.y);
|
||||||
|
device->put(' ');
|
||||||
|
txt_set_xy(screen, cursor.x - 1, cursor.y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHAR_TAB:
|
||||||
|
/* horizontal tab */
|
||||||
|
txt_get_xy(screen, &cursor);
|
||||||
|
txt_set_xy(screen, ((cursor.x >> 3) + 1) << 3, cursor.y);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHAR_NL:
|
||||||
|
/* line feed */
|
||||||
|
txt_get_xy(screen, &cursor);
|
||||||
|
txt_set_xy(screen, 0, cursor.y + 1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHAR_CR:
|
||||||
|
/* carriage return */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
device->put(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send a character to the screen without any escape code interpretation
|
||||||
|
*
|
||||||
|
* Deprecated legacy function
|
||||||
|
*
|
||||||
|
* @param screen the screen number 0 for channel A, 1 for channel B
|
||||||
|
* @param c the character to print
|
||||||
|
*/
|
||||||
|
void text_put_raw(short screen, char c) {
|
||||||
|
txt_put(screen, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print an ASCII Z string to the screen
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param c the ASCII Z string to print
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void txt_print(short screen, const char * message) {
|
||||||
|
const char * x = message;
|
||||||
|
|
||||||
|
while (*x) {
|
||||||
|
txt_put(screen, *x++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll the text in the current region
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param horizontal the number of columns to scroll (negative is left, positive is right)
|
||||||
|
* @param vertical the number of rows to scroll (negative is down, positive is up)
|
||||||
|
*/
|
||||||
|
void txt_scroll(short screen, short horizontal, short vertical) {
|
||||||
|
TRACE3("txt_scroll(%d,%d,%d)", screen, horizontal, vertical);
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->scroll) {
|
||||||
|
device->scroll(horizontal, vertical);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the current region with a character in the current color
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param c the character to fill the region with
|
||||||
|
*/
|
||||||
|
void txt_fill(short screen, char c) {
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->fill) {
|
||||||
|
device->fill(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear the screen of data
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* mode = 0: erase from the cursor to the end of the screen,
|
||||||
|
1: erase from start of the screen to the cursor,
|
||||||
|
2: erase entire screen
|
||||||
|
*/
|
||||||
|
void txt_clear(short screen, short mode) {
|
||||||
|
t_point cursor;
|
||||||
|
t_rect old_region, region;
|
||||||
|
|
||||||
|
TRACE2("txt_clear(%d,%d)", (int)screen, (int)mode);
|
||||||
|
|
||||||
|
txt_get_xy(screen, &cursor);
|
||||||
|
txt_get_region(screen, &old_region);
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 0:
|
||||||
|
// Erase from cursor to end of region
|
||||||
|
|
||||||
|
// Clear the end of the line
|
||||||
|
region.origin.x = old_region.origin.x + cursor.x;
|
||||||
|
region.origin.y = old_region.origin.y + cursor.y;
|
||||||
|
region.size.width = old_region.size.width - cursor.x;
|
||||||
|
region.size.height = 1;
|
||||||
|
txt_set_region(screen, ®ion);
|
||||||
|
txt_fill(screen, ' ');
|
||||||
|
|
||||||
|
// Clear the region after the cursor
|
||||||
|
region.origin.x = old_region.origin.x;
|
||||||
|
region.origin.y = old_region.origin.y + cursor.y + 1;
|
||||||
|
region.size.width = old_region.size.width;
|
||||||
|
region.size.height = old_region.size.height - cursor.y - 1;
|
||||||
|
txt_set_region(screen, ®ion);
|
||||||
|
txt_fill(screen, ' ');
|
||||||
|
|
||||||
|
// Restore the original region
|
||||||
|
txt_set_region(screen, &old_region);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// Erase from start of region to cursor
|
||||||
|
|
||||||
|
// Clear the region to the cursor line
|
||||||
|
region.origin.x = old_region.origin.x;
|
||||||
|
region.origin.y = old_region.origin.y;
|
||||||
|
region.size.width = old_region.size.width;
|
||||||
|
region.size.height = cursor.y;
|
||||||
|
txt_set_region(screen, ®ion);
|
||||||
|
txt_fill(screen, ' ');
|
||||||
|
|
||||||
|
// Clear the end of the line
|
||||||
|
region.origin.x = old_region.origin.x;
|
||||||
|
region.origin.y = old_region.origin.y + cursor.y;
|
||||||
|
region.size.width = cursor.x + 1;
|
||||||
|
region.size.height = 1;
|
||||||
|
txt_set_region(screen, ®ion);
|
||||||
|
txt_fill(screen, ' ');
|
||||||
|
|
||||||
|
// Restore the original region
|
||||||
|
txt_set_region(screen, &old_region);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// Erase entire region
|
||||||
|
txt_fill(screen, ' ');
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear part or all of the current line
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* mode = 0: erase from the start of the line to the cursor,
|
||||||
|
* 1: erase from cursor to end of the line,
|
||||||
|
* 2: erase entire line
|
||||||
|
*/
|
||||||
|
void txt_clear_line(short screen, short mode) {
|
||||||
|
t_point cursor;
|
||||||
|
t_rect old_region, region;
|
||||||
|
|
||||||
|
TRACE2("txt_clear_line(%d,%d)", (int)screen, (int)mode);
|
||||||
|
|
||||||
|
txt_get_xy(screen, &cursor);
|
||||||
|
txt_get_region(screen, &old_region);
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 0:
|
||||||
|
// Erase from cursor to end of line
|
||||||
|
|
||||||
|
// Clear the end of the line
|
||||||
|
region.origin.x = old_region.origin.x + cursor.x;
|
||||||
|
region.origin.y = old_region.origin.y + cursor.y;
|
||||||
|
region.size.width = old_region.size.width - cursor.x;
|
||||||
|
region.size.height = 1;
|
||||||
|
txt_set_region(screen, ®ion);
|
||||||
|
txt_fill(screen, ' ');
|
||||||
|
|
||||||
|
// Restore the original region
|
||||||
|
txt_set_region(screen, &old_region);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
// Erase from start of line to cursor
|
||||||
|
|
||||||
|
// Clear the end of the line
|
||||||
|
region.origin.x =old_region.origin.x;
|
||||||
|
region.origin.y = old_region.origin.y + cursor.y;
|
||||||
|
region.size.width = cursor.x;
|
||||||
|
region.size.height = 1;
|
||||||
|
txt_set_region(screen, ®ion);
|
||||||
|
txt_fill(screen, ' ');
|
||||||
|
|
||||||
|
// Restore the original region
|
||||||
|
txt_set_region(screen, &old_region);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
// Clear the line
|
||||||
|
region.origin.x = old_region.origin.x;
|
||||||
|
region.origin.y = old_region.origin.y + cursor.y;
|
||||||
|
region.size.width = old_region.size.width;
|
||||||
|
region.size.height = 1;
|
||||||
|
txt_set_region(screen, ®ion);
|
||||||
|
txt_fill(screen, ' ');
|
||||||
|
|
||||||
|
// Restore the original region
|
||||||
|
txt_set_region(screen, &old_region);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert a number of characters at the cursor position
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* count = the number of characters to insert
|
||||||
|
*/
|
||||||
|
void txt_insert(short screen, short count) {
|
||||||
|
t_point cursor;
|
||||||
|
t_rect old_region, region;
|
||||||
|
|
||||||
|
TRACE2("txt_clear_line(%d,%d)", (int)screen, (int)count);
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
txt_get_xy(screen, &cursor);
|
||||||
|
txt_get_region(screen, &old_region);
|
||||||
|
|
||||||
|
region.origin.x = old_region.origin.x + cursor.x;
|
||||||
|
region.origin.y = old_region.origin.y + cursor.y;
|
||||||
|
region.size.width = old_region.size.width - cursor.x;
|
||||||
|
region.size.height = 1;
|
||||||
|
txt_set_region(screen, ®ion);
|
||||||
|
txt_scroll(screen, 0 - count, 0);
|
||||||
|
txt_set_region(screen, &old_region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete a number of characters at the cursor position
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* count = the number of characters to delete
|
||||||
|
*/
|
||||||
|
void txt_delete(short screen, short count) {
|
||||||
|
t_point cursor;
|
||||||
|
t_rect old_region, region;
|
||||||
|
short left;
|
||||||
|
|
||||||
|
TRACE2("txt_delete(%d,%d)", screen, count);
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
txt_get_xy(screen, &cursor);
|
||||||
|
txt_get_region(screen, &old_region);
|
||||||
|
|
||||||
|
if (count > cursor.x) {
|
||||||
|
count = cursor.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
region.origin.x = old_region.origin.x + cursor.x;
|
||||||
|
region.origin.y = old_region.origin.y + cursor.y;
|
||||||
|
region.size.width = old_region.size.width - cursor.x;
|
||||||
|
region.size.height = 1;
|
||||||
|
txt_set_region(screen, ®ion);
|
||||||
|
txt_scroll(screen, count, 0);
|
||||||
|
txt_set_region(screen, &old_region);
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("txt_delete( returning");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the display resolutions
|
||||||
|
*
|
||||||
|
* @param screen the screen number 0 for channel A, 1 for channel B
|
||||||
|
* @param text_size the size of the screen in visible characters (may be null)
|
||||||
|
* @param pixel_size the size of the screen in pixels (may be null)
|
||||||
|
*/
|
||||||
|
SYSTEMCALL void txt_get_sizes(short screen, p_extent text_size, p_extent pixel_size) {
|
||||||
|
TRACE("txt_get_sizes");
|
||||||
|
p_txt_device device = txt_get_device(screen);
|
||||||
|
if (device) {
|
||||||
|
if (device->get_sizes) {
|
||||||
|
device->get_sizes(text_size, pixel_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
343
src/dev/txt_screen.h
Normal file
343
src/dev/txt_screen.h
Normal file
|
@ -0,0 +1,343 @@
|
||||||
|
/**
|
||||||
|
* @file txt_screen.h
|
||||||
|
*
|
||||||
|
* Uniform routines to manage the text screens
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TXT_SCREEN_H
|
||||||
|
#define __TXT_SCREEN_H
|
||||||
|
|
||||||
|
#include "sys_macros.h"
|
||||||
|
#include "sys_types.h"
|
||||||
|
|
||||||
|
#define TXT_CNT_SCREENS 5 /**< The maximum number of screens supported */
|
||||||
|
|
||||||
|
#define TXT_MODE_TEXT 0x0001 /**< The bit to enable text mode */
|
||||||
|
#define TXT_MODE_BITMAP 0x0002 /**< The bit to enable bitmap graphics mode */
|
||||||
|
#define TXT_MODE_SPRITE 0x0004 /**< The bit to enable sprite graphics mode */
|
||||||
|
#define TXT_MODE_TILE 0x0008 /**< The bit to enable tile graphics mode */
|
||||||
|
#define TXT_MODE_SLEEP 0x0010 /**< The bit to put the monitor to sleep by disabling sync */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*p_init)();
|
||||||
|
typedef const p_txt_capabilities (*p_get_capabilities)();
|
||||||
|
typedef short (*p_set_mode)(short mode);
|
||||||
|
typedef void (*p_setsizes)();
|
||||||
|
typedef short (*p_set_resolution)(short width, short height);
|
||||||
|
typedef void (*p_set_border)(short width, short height);
|
||||||
|
typedef void (*p_set_border_color)(unsigned char red, unsigned char green, unsigned char blue);
|
||||||
|
typedef short (*p_set_font)(short width, short height, const unsigned char * data);
|
||||||
|
typedef void (*p_set_cursor)(short enable, short rate, char c);
|
||||||
|
typedef void (*p_set_cursor_visible)(short enable);
|
||||||
|
typedef short (*p_set_region)(p_rect region);
|
||||||
|
typedef short (*p_set_color)(unsigned char foreground, unsigned char background);
|
||||||
|
typedef short (*p_get_color)(unsigned char * foreground, unsigned char * background);
|
||||||
|
typedef void (*p_set_xy)(short x, short y);
|
||||||
|
typedef void (*p_get_xy)(p_point position);
|
||||||
|
typedef void (*p_put)(char c);
|
||||||
|
typedef void (*p_scroll)(short horizontal, short vertical);
|
||||||
|
typedef void (*p_fill)(char c);
|
||||||
|
typedef void (*p_get_sizes)(p_extent text_size, p_extent pixel_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct s_txt_device
|
||||||
|
*
|
||||||
|
* A device driver for a text screen
|
||||||
|
*
|
||||||
|
* The driver contains basic information about the device and pointers
|
||||||
|
* to all the functions that implement actions the driver can take.
|
||||||
|
*/
|
||||||
|
typedef struct s_txt_device {
|
||||||
|
short number; /**< The unique ID of the screen */
|
||||||
|
const char * name; /**< A human-readable (mostly) name for the screen */
|
||||||
|
|
||||||
|
p_init init; /**< Pointer to the device's init function */
|
||||||
|
p_get_capabilities get_capabilities; /**< Pointer to the device's get_capabilities function */
|
||||||
|
p_set_mode set_mode; /**< Pointer to the device's set_mode function */
|
||||||
|
p_setsizes set_sizes; /**< Pointer to the device's set_sizes function */
|
||||||
|
p_set_resolution set_resolution; /**< Pointer to the device's set_resolution function */
|
||||||
|
p_set_border set_border; /**< Pointer to the device's set_border function */
|
||||||
|
p_set_border_color set_border_color; /**< Pointer to the device's set_border function */
|
||||||
|
p_set_font set_font; /**< Pointer to the device's set_font function */
|
||||||
|
p_set_region get_region; /**< Pointer to the device's get_region function */
|
||||||
|
p_set_region set_region; /**< Pointer to the device's set_region function */
|
||||||
|
p_get_color get_color; /**< Pointer to the device's get_color function */
|
||||||
|
p_set_color set_color; /**< Pointer to the device's set_color function */
|
||||||
|
p_set_cursor set_cursor; /**< Pointer to the device's set_cursor function */
|
||||||
|
p_set_cursor_visible set_cursor_visible; /**< Pointer to the device's set_cursor_visible function */
|
||||||
|
p_set_xy set_xy; /**< Pointer to the device's set_xy function */
|
||||||
|
p_get_xy get_xy; /**< Pointer to the device's get_xy function */
|
||||||
|
p_put put; /**< Pointer to the device's put function */
|
||||||
|
p_scroll scroll; /**< Pointer to the device's scroll function */
|
||||||
|
p_fill fill; /**< Pointer to the device's fill function */
|
||||||
|
p_get_sizes get_sizes; /**< Pointer to the device's get_sizes function */
|
||||||
|
} t_txt_device, *p_txt_device;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the text system.
|
||||||
|
*/
|
||||||
|
extern void txt_init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a device driver for a text screen
|
||||||
|
*
|
||||||
|
* @param device the pointer to the device driver (all will be copied into the kernel's internal storage)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
extern short txt_register(p_txt_device device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a screen
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
*/
|
||||||
|
extern void txt_init_screen(short screen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the description of a screen's capabilities
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
*
|
||||||
|
* @return a pointer to the read-only description (0 on error)
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL const p_txt_capabilities txt_get_capabilities(short screen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the display mode for the screen
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param mode a bitfield of desired display mode options
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the mode is invalid for the screen
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short txt_set_mode(short screen, short mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recalculate the size of the text screen
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the mode is invalid for the screen
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short txt_setsizes(short screen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the display resolution of the screen
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param width the desired horizontal resolution in pixels
|
||||||
|
* @param height the desired veritical resolution in pixels
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the resolution is unsupported
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short txt_set_resolution(short screen, short width, short height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the border of the screen (if supported)
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param width the horizontal size of one side of the border (0 - 32 pixels)
|
||||||
|
* @param height the vertical size of one side of the border (0 - 32 pixels)
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL void txt_set_border(short screen, short width, short height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the border of the screen (if supported)
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param red the red component of the color (0 - 255)
|
||||||
|
* @param green the green component of the color (0 - 255)
|
||||||
|
* @param blue the blue component of the color (0 - 255)
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL void txt_set_border_color(short screen, unsigned char red, unsigned char green, unsigned char blue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a font as the current font for the screen
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param width width of a character in pixels
|
||||||
|
* @param height of a character in pixels
|
||||||
|
* @param data pointer to the raw font data to be loaded
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short txt_set_font(short screen, short width, short height, const unsigned char * data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the appearance of the cursor
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param enable 0 to hide, any other number to make visible
|
||||||
|
* @param rate the blink rate for the cursor (0=1s, 1=0.5s, 2=0.25s, 3=1/5s)
|
||||||
|
* @param c the character in the current font to use as a cursor
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL void txt_set_cursor(short screen, short enable, short rate, char c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the appearance of the cursor
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param enable 0 to hide, any other number to make visible
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL void txt_set_cursor_visible(short screen, short enable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current region.
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param region pointer to a t_rect describing the rectangular region (using character cells for size and size)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the region was invalid
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short txt_get_region(short screen, p_rect region);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a region to restrict further character display, scrolling, etc.
|
||||||
|
* Note that a region of zero size will reset the region to the full size of the screen.
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param region pointer to a t_rect describing the rectangular region (using character cells for size and size)
|
||||||
|
*
|
||||||
|
* @return 0 on success, any other number means the region was invalid
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short txt_set_region(short screen, p_rect region);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the default foreground and background colors for printing
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param foreground the Text LUT index of the new current foreground color (0 - 15)
|
||||||
|
* @param background the Text LUT index of the new current background color (0 - 15)
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL short txt_set_color(short screen, unsigned char foreground, unsigned char background);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the foreground and background color for printing
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* foreground = pointer to the foreground color number
|
||||||
|
* background = pointer to the background color number
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL void txt_get_color(short screen, unsigned char * foreground, unsigned char * background);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the position of the cursor to (x, y) relative to the current region
|
||||||
|
* If the (x, y) coordinate is outside the region, it will be clipped to the region.
|
||||||
|
* If y is greater than the height of the region, the region will scroll until that relative
|
||||||
|
* position would be within view.
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param x the column for the cursor
|
||||||
|
* @param y the row for the cursor
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL void txt_set_xy(short screen, short x, short y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position of the cursor (x, y) relative to the current region
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param position pointer to a t_point record to fill out
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL void txt_get_xy(short screen, p_point position);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print a character to the current cursor position in the current color
|
||||||
|
*
|
||||||
|
* Most character codes will result in a glyph being displayed at the current
|
||||||
|
* cursor position, advancing the cursor one spot. There are some exceptions that
|
||||||
|
* will be treated as control codes:
|
||||||
|
*
|
||||||
|
* 0x08 - BS - Move the cursor back one position, erasing the character underneath
|
||||||
|
* 0x09 - HT - Move forward to the next TAB stop
|
||||||
|
* 0x0A - LF - Move the cursor down one line (line feed)
|
||||||
|
* 0x0D - CR - Move the cursor to column 0 (carriage return)
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param c the character to print
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL void txt_put(short screen, char c);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send a character to the screen without any escape code interpretation
|
||||||
|
*
|
||||||
|
* Deprecated legacy function
|
||||||
|
*
|
||||||
|
* @param screen the screen number 0 for channel A, 1 for channel B
|
||||||
|
* @param c the character to print
|
||||||
|
*/
|
||||||
|
extern void text_put_raw(short screen, char c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print an ASCII Z string to the screen
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param c the ASCII Z string to print
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL void txt_print(short screen, const char * message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll the text in the current region
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param horizontal the number of columns to scroll (negative is left, positive is right)
|
||||||
|
* @param vertical the number of rows to scroll (negative is down, positive is up)
|
||||||
|
*/
|
||||||
|
extern void txt_scroll(short screen, short horiztonal, short vertical);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill the current region with a character in the current color
|
||||||
|
*
|
||||||
|
* @param screen the number of the text device
|
||||||
|
* @param c the character to fill the region with
|
||||||
|
*/
|
||||||
|
extern void txt_fill(short screen, char c);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear the screen of data
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* mode = 0: erase from the cursor to the end of the screen,
|
||||||
|
1: erase from start of the screen to the cursor,
|
||||||
|
2: erase entire screen
|
||||||
|
*/
|
||||||
|
extern void txt_clear(short screen, short mode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear part or all of the current line
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* mode = 0: erase from the start of the line to the cursor,
|
||||||
|
* 1: erase from cursor to end of the line,
|
||||||
|
* 2: erase entire line
|
||||||
|
*/
|
||||||
|
extern void txt_clear_line(short screen, short mode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Insert a number of characters at the cursor position
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* count = the number of characters to insert
|
||||||
|
*/
|
||||||
|
extern void txt_insert(short screen, short count);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete a number of characters at the cursor position
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* screen = the screen number 0 for channel A, 1 for channel B
|
||||||
|
* count = the number of characters to delete
|
||||||
|
*/
|
||||||
|
extern void txt_delete(short screen, short count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the display resolutions
|
||||||
|
*
|
||||||
|
* @param screen the screen number 0 for channel A, 1 for channel B
|
||||||
|
* @param text_size the size of the screen in visible characters (may be null)
|
||||||
|
* @param pixel_size the size of the screen in pixels (may be null)
|
||||||
|
*/
|
||||||
|
extern SYSTEMCALL void txt_get_sizes(short screen, p_extent text_size, p_extent pixel_size);
|
||||||
|
|
||||||
|
#endif
|
475
src/dev/uart.c
Normal file
475
src/dev/uart.c
Normal file
|
@ -0,0 +1,475 @@
|
||||||
|
/*
|
||||||
|
* Definitions of the UART routines
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "errors.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "uart_reg.h"
|
||||||
|
#include "dev/channel.h"
|
||||||
|
#include "dev/uart.h"
|
||||||
|
#include "simpleio.h"
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the UART index for the given channel device
|
||||||
|
*/
|
||||||
|
short cdev_to_uart(short dev) {
|
||||||
|
return dev - CDEV_COM1;
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile unsigned char * uart_get_base(short uart) {
|
||||||
|
if (uart == 0) {
|
||||||
|
return (volatile unsigned char *)UART1_BASE;
|
||||||
|
} else {
|
||||||
|
return (volatile unsigned char *)UART2_BASE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the data transfer speed
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* uart = the number of the UART: 0 for COM1, 1 for COM2
|
||||||
|
* bps_code = the UART_* code number for the bits-per-second
|
||||||
|
*/
|
||||||
|
void uart_setbps(short uart, unsigned short bps_code) {
|
||||||
|
volatile unsigned char * uart_base = uart_get_base(uart);
|
||||||
|
|
||||||
|
if (uart_base) {
|
||||||
|
/* Enable divisor latch */
|
||||||
|
uart_base[UART_LCR] = uart_base[UART_LCR] | 0x80;
|
||||||
|
|
||||||
|
/* Set the divisor */
|
||||||
|
uart_base[UART_TRHB] = bps_code & 0xff;
|
||||||
|
uart_base[UART_TRHB+1] = (bps_code >> 8) & 0xff;
|
||||||
|
|
||||||
|
/* Disable divisor latch */
|
||||||
|
uart_base[UART_LCR] = uart_base[UART_LCR] & 0x7F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the line control register
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* uart = the number of the UART: 0 for COM1, 1 for COM2
|
||||||
|
* lcr_bits = the LCR settings
|
||||||
|
*/
|
||||||
|
void uart_setlcr(short uart, unsigned char lcr_bits) {
|
||||||
|
volatile unsigned char * uart_base = uart_get_base(uart);
|
||||||
|
|
||||||
|
if (uart_base) {
|
||||||
|
uart_base[UART_LCR] = lcr_bits; /* Set the LCR bits (without the DLL bit) */
|
||||||
|
if (uart_base[UART_LCR] != lcr_bits) {
|
||||||
|
DEBUG("LCR mismatched!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize a UART
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* uart = the number of the UART: 0 for COM1, 1 for COM2
|
||||||
|
*/
|
||||||
|
void uart_init(short uart) {
|
||||||
|
volatile unsigned char * uart_base = uart_get_base(uart);
|
||||||
|
|
||||||
|
if (uart_base) {
|
||||||
|
/* Default to 9600 bps */
|
||||||
|
uart_setbps(uart, UART_9600);
|
||||||
|
|
||||||
|
/* Set: no parity, 1 stop bit, 8 data bits */
|
||||||
|
uart_setlcr(uart, LCR_PARITY_NONE | LCR_STOPBIT_1 | LCR_DATABITS_8);
|
||||||
|
|
||||||
|
/* Enable FIFO, set for 56 byte trigger level */
|
||||||
|
uart_base[UART_FCR] = 0xC1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return true (non-zero) if the UART has data ready to read in its FIFO
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* uart = the number of the UART: 0 for COM1, 1 for COM2
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* true if there is data to read, false if there is no data.
|
||||||
|
*/
|
||||||
|
bool uart_has_bytes(short uart) {
|
||||||
|
volatile unsigned char * uart_base = uart_get_base(uart);
|
||||||
|
|
||||||
|
return uart_base && (uart_base[UART_LSR] & LSR_DATA_AVAIL) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true (non-zero) if the UART transmit FIFO is not full
|
||||||
|
*
|
||||||
|
* @param uart the number of the UART: 0 for COM1, 1 for COM2
|
||||||
|
* @return non-zero if the FIFO can accept a byte, 0 if it is full
|
||||||
|
*/
|
||||||
|
short uart_can_send(short uart) {
|
||||||
|
volatile unsigned char * uart_base = uart_get_base(uart);
|
||||||
|
|
||||||
|
if (uart_base) {
|
||||||
|
if (uart_base[UART_LSR] & LSR_XMIT_EMPTY) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send a byte to the UART. Blocks until the FIFO is ready to recieve a byte.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* uart = the number of the UART: 0 for COM1, 1 for COM2
|
||||||
|
* b = the byte to send
|
||||||
|
*/
|
||||||
|
void uart_put(short uart, unsigned char b) {
|
||||||
|
volatile unsigned char * uart_base = uart_get_base(uart);
|
||||||
|
|
||||||
|
if (uart_base) {
|
||||||
|
unsigned char status = 0;
|
||||||
|
|
||||||
|
/* Wait for the transmit buffer to be empty */
|
||||||
|
do {
|
||||||
|
status = uart_base[UART_LSR];
|
||||||
|
} while ((status & LSR_XMIT_EMPTY) == 0);
|
||||||
|
|
||||||
|
/* Send the byte */
|
||||||
|
uart_base[UART_TRHB] = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a byte from the UART. Blocks until there is data to read.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* uart = the number of the UART: 0 for COM1, 1 for COM2
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the byte read from the UART
|
||||||
|
*/
|
||||||
|
unsigned char uart_get(short uart) {
|
||||||
|
volatile unsigned char * uart_base = uart_get_base(uart);
|
||||||
|
|
||||||
|
if (uart_base) {
|
||||||
|
unsigned char status = 0;
|
||||||
|
|
||||||
|
/* Wait for there to be data available */
|
||||||
|
do {
|
||||||
|
status = uart_base[UART_LSR];
|
||||||
|
} while ((status & LSR_DATA_AVAIL) == 0);
|
||||||
|
|
||||||
|
/* Return the byte */
|
||||||
|
return uart_base[UART_TRHB];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the status of the UART
|
||||||
|
*
|
||||||
|
* @param channel the descriptor for the channel
|
||||||
|
* @return the status of the device
|
||||||
|
*/
|
||||||
|
short uart_status(p_channel chan) {
|
||||||
|
short status = 0;
|
||||||
|
|
||||||
|
// Check if there is data to be read
|
||||||
|
if (uart_has_bytes(cdev_to_uart(chan->dev))) {
|
||||||
|
status |= CDEV_STAT_READABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the FIFO is full
|
||||||
|
if (uart_can_send(cdev_to_uart(chan->dev))) {
|
||||||
|
status |= CDEV_STAT_WRITABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: reflect error bits?
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a serial connection... allow specification for bps, data size, etc.
|
||||||
|
*
|
||||||
|
* The specification provided to open is a string of four comma separated values:
|
||||||
|
* 1. Bits-per-second: 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200
|
||||||
|
* 2. Number of data bits: 5, 6, 7, 8
|
||||||
|
* 3. Stop bits: 1, or 2
|
||||||
|
* 4. Parity: NONE, ODD, EVEN, MARK, or SPACE
|
||||||
|
*
|
||||||
|
* @param chan the channel descriptor to open
|
||||||
|
* @param spec a string describing the connection to open: <bps>,<data bits>,<stop bits>,<parity Y/N>
|
||||||
|
* @param mode an unused parameter
|
||||||
|
* @return 0 on success, any other number is an error
|
||||||
|
*/
|
||||||
|
short uart_open(p_channel chan, const char * spec, short mode) {
|
||||||
|
unsigned short bps = 0, lcr = 0;
|
||||||
|
char * saveptr;
|
||||||
|
char spec_copy[80];
|
||||||
|
char *token = 0;
|
||||||
|
short i = 0;
|
||||||
|
short bps_code = 0;
|
||||||
|
short lcr_code = 0;
|
||||||
|
|
||||||
|
/* Do some basic initialization of the UART */
|
||||||
|
uart_init(cdev_to_uart(chan->dev));
|
||||||
|
|
||||||
|
// Make a local copy of the specification so we can tokenize it
|
||||||
|
strncpy(spec_copy, spec, 80);
|
||||||
|
|
||||||
|
// Get the first token
|
||||||
|
saveptr = spec_copy;
|
||||||
|
token = strtok_r(spec_copy, ",", &saveptr);
|
||||||
|
if (token) {
|
||||||
|
// Parse the bit rate token
|
||||||
|
i = atoi(token);
|
||||||
|
switch (i) {
|
||||||
|
case 300:
|
||||||
|
bps_code = UART_300;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1200:
|
||||||
|
bps_code = UART_1200;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2400:
|
||||||
|
bps_code = UART_2400;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4800:
|
||||||
|
bps_code = UART_4800;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 9600:
|
||||||
|
bps_code = UART_9600;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 19200:
|
||||||
|
bps_code = UART_19200;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 38400:
|
||||||
|
bps_code = UART_38400;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 57600:
|
||||||
|
bps_code = UART_57600;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 115200:
|
||||||
|
bps_code = UART_115200;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return ERR_BAD_ARGUMENT;
|
||||||
|
}
|
||||||
|
uart_setbps(cdev_to_uart(chan->dev), bps_code);
|
||||||
|
|
||||||
|
// Get the next token
|
||||||
|
token = strtok_r(spec_copy, ",", &saveptr);
|
||||||
|
if (token) {
|
||||||
|
// Parse the data bit count
|
||||||
|
i = atoi(token);
|
||||||
|
switch (i) {
|
||||||
|
case 5:
|
||||||
|
lcr_code = LCR_DATABITS_5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
lcr_code = LCR_DATABITS_6;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
lcr_code = LCR_DATABITS_7;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
lcr_code = LCR_DATABITS_8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log(LOG_ERROR, "uart_open: Bad data word length");
|
||||||
|
return ERR_BAD_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next token
|
||||||
|
token = strtok_r(spec_copy, ",", &saveptr);
|
||||||
|
if (token) {
|
||||||
|
// Parse the stop bit count (1 or 2)
|
||||||
|
i = atoi(token);
|
||||||
|
if (i == 1) {
|
||||||
|
lcr_code |= LCR_STOPBIT_1;
|
||||||
|
} else if (i == 2) {
|
||||||
|
lcr_code |= LCR_STOPBIT_2;
|
||||||
|
} else {
|
||||||
|
log(LOG_ERROR, "uart_open: Bad stop bits");
|
||||||
|
return ERR_BAD_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next token
|
||||||
|
token = strtok_r(spec_copy, ",", &saveptr);
|
||||||
|
if (token) {
|
||||||
|
// NONE, ODD, EVEN, MARK, or SPACE
|
||||||
|
if (strcmp(token, "NONE") == 0) {
|
||||||
|
lcr_code |= LCR_PARITY_NONE;
|
||||||
|
} else if (strcmp(token, "ODD") == 0) {
|
||||||
|
lcr_code |= LCR_PARITY_ODD;
|
||||||
|
} else if (strcmp(token, "EVEN") == 0) {
|
||||||
|
lcr_code |= LCR_PARITY_EVEN;
|
||||||
|
} else if (strcmp(token, "MARK") == 0) {
|
||||||
|
lcr_code |= LCR_PARITY_MARK;
|
||||||
|
} else if (strcmp(token, "SPACE") == 0) {
|
||||||
|
lcr_code |= LCR_PARITY_SPACE;
|
||||||
|
} else {
|
||||||
|
log(LOG_ERROR, "uart_open: Bad parity");
|
||||||
|
return ERR_BAD_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set word length, stop bit size, and parity
|
||||||
|
uart_setlcr(cdev_to_uart(chan->dev), lcr_code);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
log(LOG_ERROR, "uart_open: no parity token");
|
||||||
|
return ERR_BAD_ARGUMENT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log(LOG_ERROR, "uart_open: no stop bit token");
|
||||||
|
return ERR_BAD_ARGUMENT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log(LOG_ERROR, "uart_open: no data length token");
|
||||||
|
return ERR_BAD_ARGUMENT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log(LOG_ERROR, "uart_open: no BPS token");
|
||||||
|
return ERR_BAD_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a single char from the UART
|
||||||
|
*
|
||||||
|
* @param channel the number of the channel
|
||||||
|
* @return the value read (if negative, error)
|
||||||
|
*/
|
||||||
|
short uart_read_b(p_channel chan) {
|
||||||
|
return uart_get(cdev_to_uart(chan->dev));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read bytes from the UART
|
||||||
|
*
|
||||||
|
* @param channel the number of the channel
|
||||||
|
* @param buffer the buffer into which to copy the channel data
|
||||||
|
* @param size the size of the buffer.
|
||||||
|
* @return number of bytes read, any negative number is an error code
|
||||||
|
*/
|
||||||
|
short uart_read(p_channel chan, char * buffer, short size) {
|
||||||
|
short i = 0, count = 0;
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
buffer[i] = uart_get(cdev_to_uart(chan->dev));
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a line from the UART
|
||||||
|
*
|
||||||
|
* @param channel the number of the channel
|
||||||
|
* @param buffer the buffer into which to copy the channel data
|
||||||
|
* @param size the size of the buffer.
|
||||||
|
* @returns number of bytes read, any negative number is an error code
|
||||||
|
*/
|
||||||
|
short uart_readline(p_channel chan, char * buffer, short size) {
|
||||||
|
short i = 0, count = 0;
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
char c = uart_get(cdev_to_uart(chan->dev));
|
||||||
|
if ((c == '\n') || (c == '\r')) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buffer[i] = c;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a single unsigned char to the UART
|
||||||
|
*
|
||||||
|
* @param channel the number of the channel
|
||||||
|
* @param b the unsigned char to write
|
||||||
|
* @return 0 on success, a negative value on error
|
||||||
|
*/
|
||||||
|
short uart_write_b(p_channel chan, unsigned char c) {
|
||||||
|
uart_put(cdev_to_uart(chan->dev), c);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a bytes to the UART
|
||||||
|
*
|
||||||
|
* @param channel the number of the channel
|
||||||
|
* @param buffer the buffer containing the data to write
|
||||||
|
* @param size the size of the buffer.
|
||||||
|
* @return number of bytes written, any negative number is an error code
|
||||||
|
*/
|
||||||
|
short uart_write(p_channel chan, const char * buffer, short size) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
uart_put(cdev_to_uart(chan->dev), buffer[i]);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install the UART driver
|
||||||
|
*/
|
||||||
|
short uart_install() {
|
||||||
|
t_dev_chan dev;
|
||||||
|
short result = 0;
|
||||||
|
|
||||||
|
dev.name = "COM1";
|
||||||
|
dev.number = CDEV_COM1;
|
||||||
|
dev.init = 0;
|
||||||
|
dev.open = uart_open;
|
||||||
|
dev.close = 0;
|
||||||
|
dev.read = uart_read;
|
||||||
|
dev.readline = uart_readline;
|
||||||
|
dev.read_b = uart_read_b;
|
||||||
|
dev.write = uart_write;
|
||||||
|
dev.write_b = uart_write_b;
|
||||||
|
dev.flush = 0;
|
||||||
|
dev.seek = 0;
|
||||||
|
dev.status = uart_status;
|
||||||
|
dev.ioctrl = 0;
|
||||||
|
|
||||||
|
result = cdev_register(&dev);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev.name = "COM2";
|
||||||
|
dev.number = CDEV_COM2;
|
||||||
|
|
||||||
|
result = cdev_register(&dev);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
77
src/dev/uart.h
Normal file
77
src/dev/uart.h
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Declare low level routines for the UARTs
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __UART_H
|
||||||
|
#define __UART_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the address of the first register in the given UART
|
||||||
|
*
|
||||||
|
* @param uart the number of the UART 0 = COM1, 1 = COM2
|
||||||
|
*/
|
||||||
|
extern volatile unsigned char * uart_get_base(short uart);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the data transfer speed
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* uart = the number of the UART: 0 for COM1, 1 for COM2
|
||||||
|
* bps_code = the UART_* code number for the bits-per-second
|
||||||
|
*/
|
||||||
|
extern void uart_setbps(short uart, unsigned short bps_code);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the line control register
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* uart = the number of the UART: 0 for COM1, 1 for COM2
|
||||||
|
* lcr_bits = the LCR settings
|
||||||
|
*/
|
||||||
|
extern void uart_setlcr(short uart, unsigned char lcr_bits);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize a UART
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* uart = the number of the UART: 0 for COM1, 1 for COM2
|
||||||
|
*/
|
||||||
|
extern void uart_init(short uart);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return true (non-zero) if the UART has data ready to read in its FIFO
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* uart = the number of the UART: 0 for COM1, 1 for COM2
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* non-zero if there is data to read, 0 if there is no data.
|
||||||
|
*/
|
||||||
|
extern bool uart_has_bytes(short uart);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send a byte to the UART. Blocks until the FIFO is ready to recieve a byte.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* uart = the number of the UART: 0 for COM1, 1 for COM2
|
||||||
|
* b = the byte to send
|
||||||
|
*/
|
||||||
|
extern void uart_put(short uart, unsigned char b);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a byte from the UART. Blocks until there is data to read.
|
||||||
|
*
|
||||||
|
* Inputs:
|
||||||
|
* uart = the number of the UART: 0 for COM1, 1 for COM2
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* the byte read from the UART
|
||||||
|
*/
|
||||||
|
extern unsigned char uart_get(short uart);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install the UART driver
|
||||||
|
*/
|
||||||
|
extern short uart_install();
|
||||||
|
|
||||||
|
#endif
|
359
src/fatfs/00history.txt
Normal file
359
src/fatfs/00history.txt
Normal file
|
@ -0,0 +1,359 @@
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
Revision history of FatFs module
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
R0.00 (February 26, 2006)
|
||||||
|
|
||||||
|
Prototype.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.01 (April 29, 2006)
|
||||||
|
|
||||||
|
The first release.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.02 (June 01, 2006)
|
||||||
|
|
||||||
|
Added FAT12 support.
|
||||||
|
Removed unbuffered mode.
|
||||||
|
Fixed a problem on small (<32M) partition.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.02a (June 10, 2006)
|
||||||
|
|
||||||
|
Added a configuration option (_FS_MINIMUM).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.03 (September 22, 2006)
|
||||||
|
|
||||||
|
Added f_rename().
|
||||||
|
Changed option _FS_MINIMUM to _FS_MINIMIZE.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.03a (December 11, 2006)
|
||||||
|
|
||||||
|
Improved cluster scan algorithm to write files fast.
|
||||||
|
Fixed f_mkdir() creates incorrect directory on FAT32.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.04 (February 04, 2007)
|
||||||
|
|
||||||
|
Added f_mkfs().
|
||||||
|
Supported multiple drive system.
|
||||||
|
Changed some interfaces for multiple drive system.
|
||||||
|
Changed f_mountdrv() to f_mount().
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.04a (April 01, 2007)
|
||||||
|
|
||||||
|
Supported multiple partitions on a physical drive.
|
||||||
|
Added a capability of extending file size to f_lseek().
|
||||||
|
Added minimization level 3.
|
||||||
|
Fixed an endian sensitive code in f_mkfs().
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.04b (May 05, 2007)
|
||||||
|
|
||||||
|
Added a configuration option _USE_NTFLAG.
|
||||||
|
Added FSINFO support.
|
||||||
|
Fixed DBCS name can result FR_INVALID_NAME.
|
||||||
|
Fixed short seek (<= csize) collapses the file object.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.05 (August 25, 2007)
|
||||||
|
|
||||||
|
Changed arguments of f_read(), f_write() and f_mkfs().
|
||||||
|
Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
|
||||||
|
Fixed f_mkdir() on FAT32 creates incorrect directory.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.05a (February 03, 2008)
|
||||||
|
|
||||||
|
Added f_truncate() and f_utime().
|
||||||
|
Fixed off by one error at FAT sub-type determination.
|
||||||
|
Fixed btr in f_read() can be mistruncated.
|
||||||
|
Fixed cached sector is not flushed when create and close without write.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.06 (April 01, 2008)
|
||||||
|
|
||||||
|
Added fputc(), fputs(), fprintf() and fgets().
|
||||||
|
Improved performance of f_lseek() on moving to the same or following cluster.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.07 (April 01, 2009)
|
||||||
|
|
||||||
|
Merged Tiny-FatFs as a configuration option. (_FS_TINY)
|
||||||
|
Added long file name feature. (_USE_LFN)
|
||||||
|
Added multiple code page feature. (_CODE_PAGE)
|
||||||
|
Added re-entrancy for multitask operation. (_FS_REENTRANT)
|
||||||
|
Added auto cluster size selection to f_mkfs().
|
||||||
|
Added rewind option to f_readdir().
|
||||||
|
Changed result code of critical errors.
|
||||||
|
Renamed string functions to avoid name collision.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.07a (April 14, 2009)
|
||||||
|
|
||||||
|
Septemberarated out OS dependent code on reentrant cfg.
|
||||||
|
Added multiple sector size feature.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.07c (June 21, 2009)
|
||||||
|
|
||||||
|
Fixed f_unlink() can return FR_OK on error.
|
||||||
|
Fixed wrong cache control in f_lseek().
|
||||||
|
Added relative path feature.
|
||||||
|
Added f_chdir() and f_chdrive().
|
||||||
|
Added proper case conversion to extended character.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.07e (November 03, 2009)
|
||||||
|
|
||||||
|
Septemberarated out configuration options from ff.h to ffconf.h.
|
||||||
|
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
|
||||||
|
Fixed name matching error on the 13 character boundary.
|
||||||
|
Added a configuration option, _LFN_UNICODE.
|
||||||
|
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.08 (May 15, 2010)
|
||||||
|
|
||||||
|
Added a memory configuration option. (_USE_LFN = 3)
|
||||||
|
Added file lock feature. (_FS_SHARE)
|
||||||
|
Added fast seek feature. (_USE_FASTSEEK)
|
||||||
|
Changed some types on the API, XCHAR->TCHAR.
|
||||||
|
Changed .fname in the FILINFO structure on Unicode cfg.
|
||||||
|
String functions support UTF-8 encoding files on Unicode cfg.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.08a (August 16, 2010)
|
||||||
|
|
||||||
|
Added f_getcwd(). (_FS_RPATH = 2)
|
||||||
|
Added sector erase feature. (_USE_ERASE)
|
||||||
|
Moved file lock semaphore table from fs object to the bss.
|
||||||
|
Fixed f_mkfs() creates wrong FAT32 volume.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.08b (January 15, 2011)
|
||||||
|
|
||||||
|
Fast seek feature is also applied to f_read() and f_write().
|
||||||
|
f_lseek() reports required table size on creating CLMP.
|
||||||
|
Extended format syntax of f_printf().
|
||||||
|
Ignores duplicated directory separators in given path name.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.09 (September 06, 2011)
|
||||||
|
|
||||||
|
f_mkfs() supports multiple partition to complete the multiple partition feature.
|
||||||
|
Added f_fdisk().
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.09a (August 27, 2012)
|
||||||
|
|
||||||
|
Changed f_open() and f_opendir() reject null object pointer to avoid crash.
|
||||||
|
Changed option name _FS_SHARE to _FS_LOCK.
|
||||||
|
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.09b (January 24, 2013)
|
||||||
|
|
||||||
|
Added f_setlabel() and f_getlabel().
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.10 (October 02, 2013)
|
||||||
|
|
||||||
|
Added selection of character encoding on the file. (_STRF_ENCODE)
|
||||||
|
Added f_closedir().
|
||||||
|
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
|
||||||
|
Added forced mount feature with changes of f_mount().
|
||||||
|
Improved behavior of volume auto detection.
|
||||||
|
Improved write throughput of f_puts() and f_printf().
|
||||||
|
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write().
|
||||||
|
Fixed f_write() can be truncated when the file size is close to 4GB.
|
||||||
|
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.10a (January 15, 2014)
|
||||||
|
|
||||||
|
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
|
||||||
|
Added a configuration option of minimum sector size. (_MIN_SS)
|
||||||
|
2nd argument of f_rename() can have a drive number and it will be ignored.
|
||||||
|
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10)
|
||||||
|
Fixed f_close() invalidates the file object without volume lock.
|
||||||
|
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10)
|
||||||
|
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.10b (May 19, 2014)
|
||||||
|
|
||||||
|
Fixed a hard error in the disk I/O layer can collapse the directory entry.
|
||||||
|
Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.10c (November 09, 2014)
|
||||||
|
|
||||||
|
Added a configuration option for the platforms without RTC. (_FS_NORTC)
|
||||||
|
Changed option name _USE_ERASE to _USE_TRIM.
|
||||||
|
Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b)
|
||||||
|
Fixed a potential problem of FAT access that can appear on disk error.
|
||||||
|
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.11 (February 09, 2015)
|
||||||
|
|
||||||
|
Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
|
||||||
|
Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
|
||||||
|
Fixed _FS_NORTC option does not work properly. (appeared at R0.10c)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.11a (September 05, 2015)
|
||||||
|
|
||||||
|
Fixed wrong media change can lead a deadlock at thread-safe configuration.
|
||||||
|
Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE)
|
||||||
|
Removed some code pages actually not exist on the standard systems. (_CODE_PAGE)
|
||||||
|
Fixed errors in the case conversion teble of code page 437 and 850 (ff.c).
|
||||||
|
Fixed errors in the case conversion teble of Unicode (cc*.c).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.12 (April 12, 2016)
|
||||||
|
|
||||||
|
Added support for exFAT file system. (_FS_EXFAT)
|
||||||
|
Added f_expand(). (_USE_EXPAND)
|
||||||
|
Changed some members in FINFO structure and behavior of f_readdir().
|
||||||
|
Added an option _USE_CHMOD.
|
||||||
|
Removed an option _WORD_ACCESS.
|
||||||
|
Fixed errors in the case conversion table of Unicode (cc*.c).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.12a (July 10, 2016)
|
||||||
|
|
||||||
|
Added support for creating exFAT volume with some changes of f_mkfs().
|
||||||
|
Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed.
|
||||||
|
f_forward() is available regardless of _FS_TINY.
|
||||||
|
Fixed f_mkfs() creates wrong volume. (appeared at R0.12)
|
||||||
|
Fixed wrong memory read in create_name(). (appeared at R0.12)
|
||||||
|
Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.12b (September 04, 2016)
|
||||||
|
|
||||||
|
Made f_rename() be able to rename objects with the same name but case.
|
||||||
|
Fixed an error in the case conversion teble of code page 866. (ff.c)
|
||||||
|
Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12)
|
||||||
|
Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12)
|
||||||
|
Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12)
|
||||||
|
Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12)
|
||||||
|
Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12)
|
||||||
|
Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.12c (March 04, 2017)
|
||||||
|
|
||||||
|
Improved write throughput at the fragmented file on the exFAT volume.
|
||||||
|
Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN.
|
||||||
|
Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12)
|
||||||
|
Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.13 (May 21, 2017)
|
||||||
|
|
||||||
|
Changed heading character of configuration keywords "_" to "FF_".
|
||||||
|
Removed ASCII-only configuration, FF_CODE_PAGE = 1. Use FF_CODE_PAGE = 437 instead.
|
||||||
|
Added f_setcp(), run-time code page configuration. (FF_CODE_PAGE = 0)
|
||||||
|
Improved cluster allocation time on stretch a deep buried cluster chain.
|
||||||
|
Improved processing time of f_mkdir() with large cluster size by using FF_USE_LFN = 3.
|
||||||
|
Improved NoFatChain flag of the fragmented file to be set after it is truncated and got contiguous.
|
||||||
|
Fixed archive attribute is left not set when a file on the exFAT volume is renamed. (appeared at R0.12)
|
||||||
|
Fixed exFAT FAT entry can be collapsed when write or lseek operation to the existing file is done. (appeared at R0.12c)
|
||||||
|
Fixed creating a file can fail when a new cluster allocation to the exFAT directory occures. (appeared at R0.12c)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.13a (October 14, 2017)
|
||||||
|
|
||||||
|
Added support for UTF-8 encoding on the API. (FF_LFN_UNICODE = 2)
|
||||||
|
Added options for file name output buffer. (FF_LFN_BUF, FF_SFN_BUF).
|
||||||
|
Added dynamic memory allocation option for working buffer of f_mkfs() and f_fdisk().
|
||||||
|
Fixed f_fdisk() and f_mkfs() create the partition table with wrong CHS parameters. (appeared at R0.09)
|
||||||
|
Fixed f_unlink() can cause lost clusters at fragmented file on the exFAT volume. (appeared at R0.12c)
|
||||||
|
Fixed f_setlabel() rejects some valid characters for exFAT volume. (appeared at R0.12)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.13b (April 07, 2018)
|
||||||
|
|
||||||
|
Added support for UTF-32 encoding on the API. (FF_LFN_UNICODE = 3)
|
||||||
|
Added support for Unix style volume ID. (FF_STR_VOLUME_ID = 2)
|
||||||
|
Fixed accesing any object on the exFAT root directory beyond the cluster boundary can fail. (appeared at R0.12c)
|
||||||
|
Fixed f_setlabel() does not reject some invalid characters. (appeared at R0.09b)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.13c (October 14, 2018)
|
||||||
|
Supported stdint.h for C99 and later. (integer.h was included in ff.h)
|
||||||
|
Fixed reading a directory gets infinite loop when the last directory entry is not empty. (appeared at R0.12)
|
||||||
|
Fixed creating a sub-directory in the fragmented sub-directory on the exFAT volume collapses FAT chain of the parent directory. (appeared at R0.12)
|
||||||
|
Fixed f_getcwd() cause output buffer overrun when the buffer has a valid drive number. (appeared at R0.13b)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.14 (October 14, 2019)
|
||||||
|
Added support for 64-bit LBA and GUID partition table (FF_LBA64 = 1)
|
||||||
|
Changed some API functions, f_mkfs() and f_fdisk().
|
||||||
|
Fixed f_open() function cannot find the file with file name in length of FF_MAX_LFN characters.
|
||||||
|
Fixed f_readdir() function cannot retrieve long file names in length of FF_MAX_LFN - 1 characters.
|
||||||
|
Fixed f_readdir() function returns file names with wrong case conversion. (appeared at R0.12)
|
||||||
|
Fixed f_mkfs() function can fail to create exFAT volume in the second partition. (appeared at R0.12)
|
||||||
|
|
||||||
|
|
||||||
|
R0.14a (December 5, 2020)
|
||||||
|
Limited number of recursive calls in f_findnext().
|
||||||
|
Fixed old floppy disks formatted with MS-DOS 2.x and 3.x cannot be mounted.
|
||||||
|
Fixed some compiler warnings.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.14b (April 17, 2021)
|
||||||
|
Made FatFs uses standard library <string.h> for copy, compare and search instead of built-in string functions.
|
||||||
|
Added support for long long integer and floating point to f_printf(). (FF_STRF_LLI and FF_STRF_FP)
|
||||||
|
Made path name parser ignore the terminating separator to allow "dir/".
|
||||||
|
Improved the compatibility in Unix style path name feature.
|
||||||
|
Fixed the file gets dead-locked when f_open() failed with some conditions. (appeared at R0.12a)
|
||||||
|
Fixed f_mkfs() can create wrong exFAT volume due to a timing dependent error. (appeared at R0.12)
|
||||||
|
Fixed code page 855 cannot be set by f_setcp().
|
||||||
|
Fixed some compiler warnings.
|
||||||
|
|
||||||
|
|
21
src/fatfs/00readme.txt
Normal file
21
src/fatfs/00readme.txt
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
FatFs Module Source Files R0.14b
|
||||||
|
|
||||||
|
|
||||||
|
FILES
|
||||||
|
|
||||||
|
00readme.txt This file.
|
||||||
|
00history.txt Revision history.
|
||||||
|
ff.c FatFs module.
|
||||||
|
ffconf.h Configuration file of FatFs module.
|
||||||
|
ff.h Common include file for FatFs and application module.
|
||||||
|
diskio.h Common include file for FatFs and disk I/O module.
|
||||||
|
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
|
||||||
|
ffunicode.c Optional Unicode utility functions.
|
||||||
|
ffsystem.c An example of optional O/S related functions.
|
||||||
|
|
||||||
|
|
||||||
|
Low level disk I/O module is not included in this archive because the FatFs
|
||||||
|
module is only a generic file system layer and it does not depend on any specific
|
||||||
|
storage device. You need to provide a low level disk I/O module written to
|
||||||
|
control the storage device that attached to the target system.
|
||||||
|
|
60
src/fatfs/Makefile
Normal file
60
src/fatfs/Makefile
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
|
||||||
|
UNIT := C256U_PLUS
|
||||||
|
|
||||||
|
# Define OS-dependent variables
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
RM = del /F/Q
|
||||||
|
else
|
||||||
|
RM = rm -f
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Define model-specific variables, including tools, source files, compiler flags, etc.
|
||||||
|
|
||||||
|
ifeq ($(UNIT),C256U)
|
||||||
|
CPU=w65816
|
||||||
|
SRCS_FOR_UNIT=
|
||||||
|
CFLAGS_FOR_UNIT=-DMODEL=1 -DCPU=255 --target Foenix --code-model large --data-model large
|
||||||
|
LDFLAGS_FOR_UNIT=C256/ld_lc_c256_u.scm clib-lc-ld.a
|
||||||
|
else ifeq ($(UNIT),C256U_PLUS)
|
||||||
|
CPU=w65816
|
||||||
|
SRCS_FOR_UNIT=
|
||||||
|
CFLAGS_FOR_UNIT=-DMODEL=5 -DCPU=255 --target Foenix --code-model large --data-model large
|
||||||
|
LDFLAGS_FOR_UNIT=C256/ld_lc_c256_fmx.scm clib-lc-ld.a --rtattr printf=medium
|
||||||
|
else ifeq ($(UNIT),C256_FMX)
|
||||||
|
CPU=w65816
|
||||||
|
SRCS_FOR_UNIT=
|
||||||
|
CFLAGS_FOR_UNIT=-DMODEL=0 -DCPU=255 --target Foenix --code-model large --data-model large
|
||||||
|
LDFLAGS_FOR_UNIT=C256/ld_lc_c256_fmx.scm clib-lc-ld.a
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CPU),w65816)
|
||||||
|
CC=cc65816
|
||||||
|
AS=as65816
|
||||||
|
LD=ln65816
|
||||||
|
AR=nlib
|
||||||
|
endif
|
||||||
|
|
||||||
|
INCLUDES=-I.. -I../include
|
||||||
|
CFLAGS=$(INCLUDES) $(CFLAGS_FOR_UNIT) -l
|
||||||
|
ASFLAGS=$(INCLUDES)
|
||||||
|
|
||||||
|
SRCS = c256_diskio.c ff.c ffsystem.c ffunicode.c $(SRCS_FOR_UNIT)
|
||||||
|
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||||
|
OBJS4RM = $(subst /,\\,$(OBJS))
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
all: fatfs.a
|
||||||
|
|
||||||
|
# Build the devices library file for this model
|
||||||
|
fatfs.a: $(OBJS)
|
||||||
|
$(AR) $@ $^
|
||||||
|
|
||||||
|
# Build the object files from C
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
# Clean up after a build
|
||||||
|
clean:
|
||||||
|
$(RM) $(OBJS4RM) fatfs.a *.lst
|
152
src/fatfs/c256_diskio.c
Normal file
152
src/fatfs/c256_diskio.c
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* If a working storage control module is available, it should be */
|
||||||
|
/* attached to the FatFs via a glue function rather than modifying it. */
|
||||||
|
/* This is an example of glue functions to attach various exsisting */
|
||||||
|
/* storage control modules to the FatFs module with a defined API. */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
#include "dev/block.h"
|
||||||
|
#include "ff.h" /* Obtains integer types */
|
||||||
|
#include "diskio.h" /* Declarations of disk functions */
|
||||||
|
#include "simpleio.h"
|
||||||
|
|
||||||
|
/* Definitions of physical drive number for each drive */
|
||||||
|
#define DEV_SDC 0 /* Example: Map Ramdisk to physical drive 0 */
|
||||||
|
// #define DEV_FDC 1
|
||||||
|
// #define DEV_HDC 2
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Get Drive Status */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
DSTATUS disk_status (
|
||||||
|
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DSTATUS stat;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
TRACE("disk_status");
|
||||||
|
|
||||||
|
stat = bdev_status(pdrv);
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Initialize a Drive */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
DSTATUS disk_initialize (
|
||||||
|
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DSTATUS stat;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
TRACE("disk_initialize");
|
||||||
|
|
||||||
|
return bdev_init(pdrv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Read Sector(s) */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
DRESULT disk_read (
|
||||||
|
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||||
|
BYTE *buff, /* Data buffer to store read data */
|
||||||
|
LBA_t sector, /* Start sector in LBA */
|
||||||
|
UINT count /* Number of sectors to read */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DRESULT res;
|
||||||
|
int result;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
TRACE("disk_read");
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
result = bdev_read(pdrv, sector, buff, 512);
|
||||||
|
if (result < 0) {
|
||||||
|
log_num(LOG_ERROR, "disk_read error: ", result);
|
||||||
|
if (result == ERR_MEDIA_CHANGE) {
|
||||||
|
log(LOG_ERROR, "disk changed.");
|
||||||
|
return RES_NOTRDY;
|
||||||
|
} else {
|
||||||
|
log(LOG_ERROR, "gerneral error");
|
||||||
|
return RES_PARERR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sector++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Write Sector(s) */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if FF_FS_READONLY == 0
|
||||||
|
|
||||||
|
DRESULT disk_write (
|
||||||
|
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||||
|
const BYTE *buff, /* Data to be written */
|
||||||
|
LBA_t sector, /* Start sector in LBA */
|
||||||
|
UINT count /* Number of sectors to write */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DRESULT res;
|
||||||
|
int i;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
TRACE("disk_write");
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
result = bdev_write(pdrv, sector, buff, 512);
|
||||||
|
if (result < 0) {
|
||||||
|
return RES_PARERR;
|
||||||
|
} else {
|
||||||
|
sector += result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Miscellaneous Functions */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
DRESULT disk_ioctl (
|
||||||
|
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||||
|
BYTE cmd, /* Control code */
|
||||||
|
void *buff /* Buffer to send/receive control data */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DRESULT res;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
TRACE("disk_ioctl");
|
||||||
|
|
||||||
|
result = bdev_ioctrl(pdrv, cmd, buff, 0);
|
||||||
|
if (result < 0) {
|
||||||
|
return RES_PARERR;
|
||||||
|
} else {
|
||||||
|
return RES_OK;
|
||||||
|
}
|
||||||
|
}
|
229
src/fatfs/diskio.bak
Normal file
229
src/fatfs/diskio.bak
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* If a working storage control module is available, it should be */
|
||||||
|
/* attached to the FatFs via a glue function rather than modifying it. */
|
||||||
|
/* This is an example of glue functions to attach various exsisting */
|
||||||
|
/* storage control modules to the FatFs module with a defined API. */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "ff.h" /* Obtains integer types */
|
||||||
|
#include "diskio.h" /* Declarations of disk functions */
|
||||||
|
|
||||||
|
/* Definitions of physical drive number for each drive */
|
||||||
|
#define DEV_RAM 0 /* Example: Map Ramdisk to physical drive 0 */
|
||||||
|
#define DEV_MMC 1 /* Example: Map MMC/SD card to physical drive 1 */
|
||||||
|
#define DEV_USB 2 /* Example: Map USB MSD to physical drive 2 */
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Get Drive Status */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
DSTATUS disk_status (
|
||||||
|
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DSTATUS stat;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
switch (pdrv) {
|
||||||
|
case DEV_RAM :
|
||||||
|
result = RAM_disk_status();
|
||||||
|
|
||||||
|
// translate the reslut code here
|
||||||
|
|
||||||
|
return stat;
|
||||||
|
|
||||||
|
case DEV_MMC :
|
||||||
|
result = MMC_disk_status();
|
||||||
|
|
||||||
|
// translate the reslut code here
|
||||||
|
|
||||||
|
return stat;
|
||||||
|
|
||||||
|
case DEV_USB :
|
||||||
|
result = USB_disk_status();
|
||||||
|
|
||||||
|
// translate the reslut code here
|
||||||
|
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
return STA_NOINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Inidialize a Drive */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
DSTATUS disk_initialize (
|
||||||
|
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DSTATUS stat;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
switch (pdrv) {
|
||||||
|
case DEV_RAM :
|
||||||
|
result = RAM_disk_initialize();
|
||||||
|
|
||||||
|
// translate the reslut code here
|
||||||
|
|
||||||
|
return stat;
|
||||||
|
|
||||||
|
case DEV_MMC :
|
||||||
|
result = MMC_disk_initialize();
|
||||||
|
|
||||||
|
// translate the reslut code here
|
||||||
|
|
||||||
|
return stat;
|
||||||
|
|
||||||
|
case DEV_USB :
|
||||||
|
result = USB_disk_initialize();
|
||||||
|
|
||||||
|
// translate the reslut code here
|
||||||
|
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
return STA_NOINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Read Sector(s) */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
DRESULT disk_read (
|
||||||
|
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||||
|
BYTE *buff, /* Data buffer to store read data */
|
||||||
|
LBA_t sector, /* Start sector in LBA */
|
||||||
|
UINT count /* Number of sectors to read */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DRESULT res;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
switch (pdrv) {
|
||||||
|
case DEV_RAM :
|
||||||
|
// translate the arguments here
|
||||||
|
|
||||||
|
result = RAM_disk_read(buff, sector, count);
|
||||||
|
|
||||||
|
// translate the reslut code here
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
case DEV_MMC :
|
||||||
|
// translate the arguments here
|
||||||
|
|
||||||
|
result = MMC_disk_read(buff, sector, count);
|
||||||
|
|
||||||
|
// translate the reslut code here
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
case DEV_USB :
|
||||||
|
// translate the arguments here
|
||||||
|
|
||||||
|
result = USB_disk_read(buff, sector, count);
|
||||||
|
|
||||||
|
// translate the reslut code here
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RES_PARERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Write Sector(s) */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if FF_FS_READONLY == 0
|
||||||
|
|
||||||
|
DRESULT disk_write (
|
||||||
|
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||||
|
const BYTE *buff, /* Data to be written */
|
||||||
|
LBA_t sector, /* Start sector in LBA */
|
||||||
|
UINT count /* Number of sectors to write */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DRESULT res;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
switch (pdrv) {
|
||||||
|
case DEV_RAM :
|
||||||
|
// translate the arguments here
|
||||||
|
|
||||||
|
result = RAM_disk_write(buff, sector, count);
|
||||||
|
|
||||||
|
// translate the reslut code here
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
case DEV_MMC :
|
||||||
|
// translate the arguments here
|
||||||
|
|
||||||
|
result = MMC_disk_write(buff, sector, count);
|
||||||
|
|
||||||
|
// translate the reslut code here
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
case DEV_USB :
|
||||||
|
// translate the arguments here
|
||||||
|
|
||||||
|
result = USB_disk_write(buff, sector, count);
|
||||||
|
|
||||||
|
// translate the reslut code here
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RES_PARERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Miscellaneous Functions */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
DRESULT disk_ioctl (
|
||||||
|
BYTE pdrv, /* Physical drive nmuber (0..) */
|
||||||
|
BYTE cmd, /* Control code */
|
||||||
|
void *buff /* Buffer to send/receive control data */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DRESULT res;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
switch (pdrv) {
|
||||||
|
case DEV_RAM :
|
||||||
|
|
||||||
|
// Process of the command for the RAM drive
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
case DEV_MMC :
|
||||||
|
|
||||||
|
// Process of the command for the MMC/SD card
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
case DEV_USB :
|
||||||
|
|
||||||
|
// Process of the command the USB drive
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RES_PARERR;
|
||||||
|
}
|
||||||
|
|
77
src/fatfs/diskio.h
Normal file
77
src/fatfs/diskio.h
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/*-----------------------------------------------------------------------/
|
||||||
|
/ Low level disk interface modlue include file (C)ChaN, 2019 /
|
||||||
|
/-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef _DISKIO_DEFINED
|
||||||
|
#define _DISKIO_DEFINED
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Status of Disk Functions */
|
||||||
|
typedef BYTE DSTATUS;
|
||||||
|
|
||||||
|
/* Results of Disk Functions */
|
||||||
|
typedef enum {
|
||||||
|
RES_OK = 0, /* 0: Successful */
|
||||||
|
RES_ERROR, /* 1: R/W Error */
|
||||||
|
RES_WRPRT, /* 2: Write Protected */
|
||||||
|
RES_NOTRDY, /* 3: Not Ready */
|
||||||
|
RES_PARERR /* 4: Invalid Parameter */
|
||||||
|
} DRESULT;
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------*/
|
||||||
|
/* Prototypes for disk control functions */
|
||||||
|
|
||||||
|
|
||||||
|
DSTATUS disk_initialize (BYTE pdrv);
|
||||||
|
DSTATUS disk_status (BYTE pdrv);
|
||||||
|
DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
|
||||||
|
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
|
||||||
|
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||||
|
|
||||||
|
|
||||||
|
/* Disk Status Bits (DSTATUS) */
|
||||||
|
|
||||||
|
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||||||
|
#define STA_NODISK 0x02 /* No medium in the drive */
|
||||||
|
#define STA_PROTECT 0x04 /* Write protected */
|
||||||
|
|
||||||
|
|
||||||
|
/* Command code for disk_ioctrl fucntion */
|
||||||
|
|
||||||
|
/* Generic command (Used by FatFs) */
|
||||||
|
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
|
||||||
|
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
|
||||||
|
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
|
||||||
|
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
|
||||||
|
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
|
||||||
|
|
||||||
|
/* Generic command (Not used by FatFs) */
|
||||||
|
#define CTRL_POWER 5 /* Get/Set power status */
|
||||||
|
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
|
||||||
|
#define CTRL_EJECT 7 /* Eject media */
|
||||||
|
#define CTRL_FORMAT 8 /* Create physical format on the media */
|
||||||
|
|
||||||
|
/* MMC/SDC specific ioctl command */
|
||||||
|
#define MMC_GET_TYPE 10 /* Get card type */
|
||||||
|
#define MMC_GET_CSD 11 /* Get CSD */
|
||||||
|
#define MMC_GET_CID 12 /* Get CID */
|
||||||
|
#define MMC_GET_OCR 13 /* Get OCR */
|
||||||
|
#define MMC_GET_SDSTAT 14 /* Get SD status */
|
||||||
|
#define ISDIO_READ 55 /* Read data form SD iSDIO register */
|
||||||
|
#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
|
||||||
|
#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
|
||||||
|
|
||||||
|
/* ATA/CF specific ioctl command */
|
||||||
|
#define ATA_GET_REV 20 /* Get F/W revision */
|
||||||
|
#define ATA_GET_MODEL 21 /* Get model name */
|
||||||
|
#define ATA_GET_SN 22 /* Get serial number */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
6982
src/fatfs/ff.c
Normal file
6982
src/fatfs/ff.c
Normal file
File diff suppressed because it is too large
Load diff
422
src/fatfs/ff.h
Normal file
422
src/fatfs/ff.h
Normal file
|
@ -0,0 +1,422 @@
|
||||||
|
/*----------------------------------------------------------------------------/
|
||||||
|
/ FatFs - Generic FAT Filesystem module R0.14b /
|
||||||
|
/-----------------------------------------------------------------------------/
|
||||||
|
/
|
||||||
|
/ Copyright (C) 2021, ChaN, all right reserved.
|
||||||
|
/
|
||||||
|
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||||
|
/ source and binary forms, with or without modification, are permitted provided
|
||||||
|
/ that the following condition is met:
|
||||||
|
|
||||||
|
/ 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
/ this condition and the following disclaimer.
|
||||||
|
/
|
||||||
|
/ This software is provided by the copyright holder and contributors "AS IS"
|
||||||
|
/ and any warranties related to this software are DISCLAIMED.
|
||||||
|
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
||||||
|
/ by use of this software.
|
||||||
|
/
|
||||||
|
/----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FF_DEFINED
|
||||||
|
#define FF_DEFINED 86631 /* Revision ID */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ffconf.h" /* FatFs configuration options */
|
||||||
|
|
||||||
|
#if FF_DEFINED != FFCONF_DEF
|
||||||
|
#error Wrong configuration file (ffconf.h).
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Integer types used for FatFs API */
|
||||||
|
|
||||||
|
#if defined(_WIN32) /* Windows VC++ (for development only) */
|
||||||
|
#define FF_INTDEF 2
|
||||||
|
#include <windows.h>
|
||||||
|
typedef unsigned __int64 QWORD;
|
||||||
|
#include <float.h>
|
||||||
|
#define isnan(v) _isnan(v)
|
||||||
|
#define isinf(v) (!_finite(v))
|
||||||
|
|
||||||
|
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
|
||||||
|
#define FF_INTDEF 2
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
|
||||||
|
typedef unsigned char BYTE; /* char must be 8-bit */
|
||||||
|
typedef uint16_t WORD; /* 16-bit unsigned integer */
|
||||||
|
typedef uint32_t DWORD; /* 32-bit unsigned integer */
|
||||||
|
typedef uint64_t QWORD; /* 64-bit unsigned integer */
|
||||||
|
typedef WORD WCHAR; /* UTF-16 character type */
|
||||||
|
|
||||||
|
#else /* Earlier than C99 */
|
||||||
|
#define FF_INTDEF 1
|
||||||
|
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
|
||||||
|
typedef unsigned char BYTE; /* char must be 8-bit */
|
||||||
|
typedef unsigned short WORD; /* 16-bit unsigned integer */
|
||||||
|
typedef unsigned long DWORD; /* 32-bit unsigned integer */
|
||||||
|
typedef WORD WCHAR; /* UTF-16 character type */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Type of file size and LBA variables */
|
||||||
|
|
||||||
|
#if FF_FS_EXFAT
|
||||||
|
#if FF_INTDEF != 2
|
||||||
|
#error exFAT feature wants C99 or later
|
||||||
|
#endif
|
||||||
|
typedef QWORD FSIZE_t;
|
||||||
|
#if FF_LBA64
|
||||||
|
typedef QWORD LBA_t;
|
||||||
|
#else
|
||||||
|
typedef DWORD LBA_t;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#if FF_LBA64
|
||||||
|
#error exFAT needs to be enabled when enable 64-bit LBA
|
||||||
|
#endif
|
||||||
|
typedef DWORD FSIZE_t;
|
||||||
|
typedef DWORD LBA_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Type of path name strings on FatFs API (TCHAR) */
|
||||||
|
|
||||||
|
#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */
|
||||||
|
typedef WCHAR TCHAR;
|
||||||
|
#define _T(x) L ## x
|
||||||
|
#define _TEXT(x) L ## x
|
||||||
|
#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */
|
||||||
|
typedef char TCHAR;
|
||||||
|
#define _T(x) u8 ## x
|
||||||
|
#define _TEXT(x) u8 ## x
|
||||||
|
#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */
|
||||||
|
typedef DWORD TCHAR;
|
||||||
|
#define _T(x) U ## x
|
||||||
|
#define _TEXT(x) U ## x
|
||||||
|
#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3)
|
||||||
|
#error Wrong FF_LFN_UNICODE setting
|
||||||
|
#else /* ANSI/OEM code in SBCS/DBCS */
|
||||||
|
typedef char TCHAR;
|
||||||
|
#define _T(x) x
|
||||||
|
#define _TEXT(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Definitions of volume management */
|
||||||
|
|
||||||
|
#if FF_MULTI_PARTITION /* Multiple partition configuration */
|
||||||
|
typedef struct {
|
||||||
|
BYTE pd; /* Physical drive number */
|
||||||
|
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
|
||||||
|
} PARTITION;
|
||||||
|
extern PARTITION VolToPart[]; /* Volume - Partition mapping table */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FF_STR_VOLUME_ID
|
||||||
|
#ifndef FF_VOLUME_STRS
|
||||||
|
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Filesystem object structure (FATFS) */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BYTE fs_type; /* Filesystem type (0:not mounted) */
|
||||||
|
BYTE pdrv; /* Associated physical drive */
|
||||||
|
BYTE n_fats; /* Number of FATs (1 or 2) */
|
||||||
|
BYTE wflag; /* win[] flag (b0:dirty) */
|
||||||
|
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
|
||||||
|
WORD id; /* Volume mount ID */
|
||||||
|
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
|
||||||
|
WORD csize; /* Cluster size [sectors] */
|
||||||
|
#if FF_MAX_SS != FF_MIN_SS
|
||||||
|
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
||||||
|
#endif
|
||||||
|
#if FF_USE_LFN
|
||||||
|
WCHAR* lfnbuf; /* LFN working buffer */
|
||||||
|
#endif
|
||||||
|
#if FF_FS_EXFAT
|
||||||
|
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
|
||||||
|
#endif
|
||||||
|
#if FF_FS_REENTRANT
|
||||||
|
FF_SYNC_t sobj; /* Identifier of sync object */
|
||||||
|
#endif
|
||||||
|
#if !FF_FS_READONLY
|
||||||
|
DWORD last_clst; /* Last allocated cluster */
|
||||||
|
DWORD free_clst; /* Number of free clusters */
|
||||||
|
#endif
|
||||||
|
#if FF_FS_RPATH
|
||||||
|
DWORD cdir; /* Current directory start cluster (0:root) */
|
||||||
|
#if FF_FS_EXFAT
|
||||||
|
DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
|
||||||
|
DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
|
||||||
|
DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
|
||||||
|
DWORD fsize; /* Size of an FAT [sectors] */
|
||||||
|
LBA_t volbase; /* Volume base sector */
|
||||||
|
LBA_t fatbase; /* FAT base sector */
|
||||||
|
LBA_t dirbase; /* Root directory base sector/cluster */
|
||||||
|
LBA_t database; /* Data base sector */
|
||||||
|
#if FF_FS_EXFAT
|
||||||
|
LBA_t bitbase; /* Allocation bitmap base sector */
|
||||||
|
#endif
|
||||||
|
LBA_t winsect; /* Current sector appearing in the win[] */
|
||||||
|
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||||
|
} FATFS;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Object ID and allocation information (FFOBJID) */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FATFS* fs; /* Pointer to the hosting volume of this object */
|
||||||
|
WORD id; /* Hosting volume mount ID */
|
||||||
|
BYTE attr; /* Object attribute */
|
||||||
|
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
|
||||||
|
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
|
||||||
|
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||||
|
#if FF_FS_EXFAT
|
||||||
|
DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */
|
||||||
|
DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */
|
||||||
|
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
|
||||||
|
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
|
||||||
|
DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */
|
||||||
|
#endif
|
||||||
|
#if FF_FS_LOCK
|
||||||
|
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||||
|
#endif
|
||||||
|
} FFOBJID;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* File object structure (FIL) */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||||
|
BYTE flag; /* File status flags */
|
||||||
|
BYTE err; /* Abort flag (error code) */
|
||||||
|
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
||||||
|
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
|
||||||
|
LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */
|
||||||
|
#if !FF_FS_READONLY
|
||||||
|
LBA_t dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
|
||||||
|
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
|
||||||
|
#endif
|
||||||
|
#if FF_USE_FASTSEEK
|
||||||
|
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||||
|
#endif
|
||||||
|
#if !FF_FS_TINY
|
||||||
|
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||||
|
#endif
|
||||||
|
} FIL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Directory object structure (DIR) */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FFOBJID obj; /* Object identifier */
|
||||||
|
DWORD dptr; /* Current read/write offset */
|
||||||
|
DWORD clust; /* Current cluster */
|
||||||
|
LBA_t sect; /* Current sector (0:Read operation has terminated) */
|
||||||
|
BYTE* dir; /* Pointer to the directory item in the win[] */
|
||||||
|
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
|
||||||
|
#if FF_USE_LFN
|
||||||
|
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
||||||
|
#endif
|
||||||
|
#if FF_USE_FIND
|
||||||
|
const TCHAR* pat; /* Pointer to the name matching pattern */
|
||||||
|
#endif
|
||||||
|
} DIR;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* File information structure (FILINFO) */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
FSIZE_t fsize; /* File size */
|
||||||
|
WORD fdate; /* Modified date */
|
||||||
|
WORD ftime; /* Modified time */
|
||||||
|
BYTE fattrib; /* File attribute */
|
||||||
|
#if FF_USE_LFN
|
||||||
|
TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */
|
||||||
|
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
|
||||||
|
#else
|
||||||
|
TCHAR fname[12 + 1]; /* File name */
|
||||||
|
#endif
|
||||||
|
} FILINFO;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Format parameter structure (MKFS_PARM) */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */
|
||||||
|
BYTE n_fat; /* Number of FATs */
|
||||||
|
UINT align; /* Data area alignment (sector) */
|
||||||
|
UINT n_root; /* Number of root directory entries */
|
||||||
|
DWORD au_size; /* Cluster size (byte) */
|
||||||
|
} MKFS_PARM;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* File function return code (FRESULT) */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FR_OK = 0, /* (0) Succeeded */
|
||||||
|
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
|
||||||
|
FR_INT_ERR, /* (2) Assertion failed */
|
||||||
|
FR_NOT_READY, /* (3) The physical drive cannot work */
|
||||||
|
FR_NO_FILE, /* (4) Could not find the file */
|
||||||
|
FR_NO_PATH, /* (5) Could not find the path */
|
||||||
|
FR_INVALID_NAME, /* (6) The path name format is invalid */
|
||||||
|
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
|
||||||
|
FR_EXIST, /* (8) Access denied due to prohibited access */
|
||||||
|
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
|
||||||
|
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
|
||||||
|
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
||||||
|
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
||||||
|
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
||||||
|
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
|
||||||
|
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||||
|
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||||
|
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||||
|
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
|
||||||
|
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||||
|
} FRESULT;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------*/
|
||||||
|
/* FatFs module application interface */
|
||||||
|
|
||||||
|
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
||||||
|
FRESULT f_close (FIL* fp); /* Close an open file object */
|
||||||
|
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
|
||||||
|
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
|
||||||
|
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
|
||||||
|
FRESULT f_truncate (FIL* fp); /* Truncate the file */
|
||||||
|
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
|
||||||
|
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
||||||
|
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
||||||
|
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
||||||
|
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
|
||||||
|
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
|
||||||
|
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
|
||||||
|
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
||||||
|
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
||||||
|
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
||||||
|
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
|
||||||
|
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
|
||||||
|
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
||||||
|
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
||||||
|
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
||||||
|
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
|
||||||
|
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||||
|
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
||||||
|
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||||
|
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
|
||||||
|
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||||
|
FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */
|
||||||
|
FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */
|
||||||
|
FRESULT f_setcp (WORD cp); /* Set current code page */
|
||||||
|
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
||||||
|
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
||||||
|
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
||||||
|
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
|
||||||
|
|
||||||
|
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
|
||||||
|
#define f_error(fp) ((fp)->err)
|
||||||
|
#define f_tell(fp) ((fp)->fptr)
|
||||||
|
#define f_size(fp) ((fp)->obj.objsize)
|
||||||
|
#define f_rewind(fp) f_lseek((fp), 0)
|
||||||
|
#define f_rewinddir(dp) f_readdir((dp), 0)
|
||||||
|
#define f_rmdir(path) f_unlink(path)
|
||||||
|
#define f_unmount(path) f_mount(0, path, 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------*/
|
||||||
|
/* Additional user defined functions */
|
||||||
|
|
||||||
|
/* RTC function */
|
||||||
|
#if !FF_FS_READONLY && !FF_FS_NORTC
|
||||||
|
DWORD get_fattime (void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* LFN support functions */
|
||||||
|
#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */
|
||||||
|
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
|
||||||
|
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
|
||||||
|
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
|
||||||
|
#endif
|
||||||
|
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
||||||
|
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
||||||
|
void ff_memfree (void* mblock); /* Free memory block */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Sync functions */
|
||||||
|
#if FF_FS_REENTRANT
|
||||||
|
int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */
|
||||||
|
int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */
|
||||||
|
void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */
|
||||||
|
int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------*/
|
||||||
|
/* Flags and offset address */
|
||||||
|
|
||||||
|
|
||||||
|
/* File access mode and open method flags (3rd argument of f_open) */
|
||||||
|
#define FA_READ 0x01
|
||||||
|
#define FA_WRITE 0x02
|
||||||
|
#define FA_OPEN_EXISTING 0x00
|
||||||
|
#define FA_CREATE_NEW 0x04
|
||||||
|
#define FA_CREATE_ALWAYS 0x08
|
||||||
|
#define FA_OPEN_ALWAYS 0x10
|
||||||
|
#define FA_OPEN_APPEND 0x30
|
||||||
|
|
||||||
|
/* Fast seek controls (2nd argument of f_lseek) */
|
||||||
|
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
|
||||||
|
|
||||||
|
/* Format options (2nd argument of f_mkfs) */
|
||||||
|
#define FM_FAT 0x01
|
||||||
|
#define FM_FAT32 0x02
|
||||||
|
#define FM_EXFAT 0x04
|
||||||
|
#define FM_ANY 0x07
|
||||||
|
#define FM_SFD 0x08
|
||||||
|
|
||||||
|
/* Filesystem type (FATFS.fs_type) */
|
||||||
|
#define FS_FAT12 1
|
||||||
|
#define FS_FAT16 2
|
||||||
|
#define FS_FAT32 3
|
||||||
|
#define FS_EXFAT 4
|
||||||
|
|
||||||
|
/* File attribute bits for directory entry (FILINFO.fattrib) */
|
||||||
|
#define AM_RDO 0x01 /* Read only */
|
||||||
|
#define AM_HID 0x02 /* Hidden */
|
||||||
|
#define AM_SYS 0x04 /* System */
|
||||||
|
#define AM_DIR 0x10 /* Directory */
|
||||||
|
#define AM_ARC 0x20 /* Archive */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* FF_DEFINED */
|
300
src/fatfs/ffconf.h
Normal file
300
src/fatfs/ffconf.h
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ FatFs Functional Configurations
|
||||||
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define FFCONF_DEF 86631 /* Revision ID */
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ Function Configurations
|
||||||
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define FF_FS_READONLY 0
|
||||||
|
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
||||||
|
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
|
||||||
|
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
|
||||||
|
/ and optional writing functions as well. */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_FS_MINIMIZE 0
|
||||||
|
/* This option defines minimization level to remove some basic API functions.
|
||||||
|
/
|
||||||
|
/ 0: Basic functions are fully enabled.
|
||||||
|
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
|
||||||
|
/ are removed.
|
||||||
|
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
|
||||||
|
/ 3: f_lseek() function is removed in addition to 2. */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_USE_FIND 2
|
||||||
|
/* This option switches filtered directory read functions, f_findfirst() and
|
||||||
|
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_USE_MKFS 1
|
||||||
|
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_USE_FASTSEEK 0
|
||||||
|
/* This option switches fast seek function. (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_USE_EXPAND 0
|
||||||
|
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_USE_CHMOD 0
|
||||||
|
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
||||||
|
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_USE_LABEL 1
|
||||||
|
/* This option switches volume label functions, f_getlabel() and f_setlabel().
|
||||||
|
/ (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_USE_FORWARD 0
|
||||||
|
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_USE_STRFUNC 1
|
||||||
|
#define FF_PRINT_LLI 0
|
||||||
|
#define FF_PRINT_FLOAT 0
|
||||||
|
#define FF_STRF_ENCODE 0
|
||||||
|
/* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and
|
||||||
|
/ f_printf().
|
||||||
|
/
|
||||||
|
/ 0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect.
|
||||||
|
/ 1: Enable without LF-CRLF conversion.
|
||||||
|
/ 2: Enable with LF-CRLF conversion.
|
||||||
|
/
|
||||||
|
/ FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2
|
||||||
|
makes f_printf() support floating point argument. These features want C99 or later.
|
||||||
|
/ When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character
|
||||||
|
/ encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE
|
||||||
|
/ to be read/written via those functions.
|
||||||
|
/
|
||||||
|
/ 0: ANSI/OEM in current CP
|
||||||
|
/ 1: Unicode in UTF-16LE
|
||||||
|
/ 2: Unicode in UTF-16BE
|
||||||
|
/ 3: Unicode in UTF-8
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ Locale and Namespace Configurations
|
||||||
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define FF_CODE_PAGE 437
|
||||||
|
/* This option specifies the OEM code page to be used on the target system.
|
||||||
|
/ Incorrect code page setting can cause a file open failure.
|
||||||
|
/
|
||||||
|
/ 437 - U.S.
|
||||||
|
/ 720 - Arabic
|
||||||
|
/ 737 - Greek
|
||||||
|
/ 771 - KBL
|
||||||
|
/ 775 - Baltic
|
||||||
|
/ 850 - Latin 1
|
||||||
|
/ 852 - Latin 2
|
||||||
|
/ 855 - Cyrillic
|
||||||
|
/ 857 - Turkish
|
||||||
|
/ 860 - Portuguese
|
||||||
|
/ 861 - Icelandic
|
||||||
|
/ 862 - Hebrew
|
||||||
|
/ 863 - Canadian French
|
||||||
|
/ 864 - Arabic
|
||||||
|
/ 865 - Nordic
|
||||||
|
/ 866 - Russian
|
||||||
|
/ 869 - Greek 2
|
||||||
|
/ 932 - Japanese (DBCS)
|
||||||
|
/ 936 - Simplified Chinese (DBCS)
|
||||||
|
/ 949 - Korean (DBCS)
|
||||||
|
/ 950 - Traditional Chinese (DBCS)
|
||||||
|
/ 0 - Include all code pages above and configured by f_setcp()
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_USE_LFN 1
|
||||||
|
#define FF_MAX_LFN 255
|
||||||
|
/* The FF_USE_LFN switches the support for LFN (long file name).
|
||||||
|
/
|
||||||
|
/ 0: Disable LFN. FF_MAX_LFN has no effect.
|
||||||
|
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
|
||||||
|
/ 2: Enable LFN with dynamic working buffer on the STACK.
|
||||||
|
/ 3: Enable LFN with dynamic working buffer on the HEAP.
|
||||||
|
/
|
||||||
|
/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
|
||||||
|
/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
|
||||||
|
/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
|
||||||
|
/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
|
||||||
|
/ be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN
|
||||||
|
/ specification.
|
||||||
|
/ When use stack for the working buffer, take care on stack overflow. When use heap
|
||||||
|
/ memory for the working buffer, memory management functions, ff_memalloc() and
|
||||||
|
/ ff_memfree() exemplified in ffsystem.c, need to be added to the project. */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_LFN_UNICODE 0
|
||||||
|
/* This option switches the character encoding on the API when LFN is enabled.
|
||||||
|
/
|
||||||
|
/ 0: ANSI/OEM in current CP (TCHAR = char)
|
||||||
|
/ 1: Unicode in UTF-16 (TCHAR = WCHAR)
|
||||||
|
/ 2: Unicode in UTF-8 (TCHAR = char)
|
||||||
|
/ 3: Unicode in UTF-32 (TCHAR = DWORD)
|
||||||
|
/
|
||||||
|
/ Also behavior of string I/O functions will be affected by this option.
|
||||||
|
/ When LFN is not enabled, this option has no effect. */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_LFN_BUF 255
|
||||||
|
#define FF_SFN_BUF 12
|
||||||
|
/* This set of options defines size of file name members in the FILINFO structure
|
||||||
|
/ which is used to read out directory items. These values should be suffcient for
|
||||||
|
/ the file names to read. The maximum possible length of the read file name depends
|
||||||
|
/ on character encoding. When LFN is not enabled, these options have no effect. */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_FS_RPATH 2
|
||||||
|
/* This option configures support for relative path.
|
||||||
|
/
|
||||||
|
/ 0: Disable relative path and remove related functions.
|
||||||
|
/ 1: Enable relative path. f_chdir() and f_chdrive() are available.
|
||||||
|
/ 2: f_getcwd() function is available in addition to 1.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ Drive/Volume Configurations
|
||||||
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define FF_VOLUMES 1
|
||||||
|
/* Number of volumes (logical drives) to be used. (1-10) */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_STR_VOLUME_ID 2
|
||||||
|
// #define FF_VOLUME_STRS "S,F,H"
|
||||||
|
/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
|
||||||
|
/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
|
||||||
|
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
|
||||||
|
/ logical drives. Number of items must not be less than FF_VOLUMES. Valid
|
||||||
|
/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
|
||||||
|
/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
|
||||||
|
/ not defined, a user defined volume string table needs to be defined as:
|
||||||
|
/
|
||||||
|
/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FF_MULTI_PARTITION 0
|
||||||
|
/* This option switches support for multiple volumes on the physical drive.
|
||||||
|
/ By default (0), each logical drive number is bound to the same physical drive
|
||||||
|
/ number and only an FAT volume found on the physical drive will be mounted.
|
||||||
|
/ When this function is enabled (1), each logical drive number can be bound to
|
||||||
|
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
|
||||||
|
/ funciton will be available. */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_MIN_SS 512
|
||||||
|
#define FF_MAX_SS 512
|
||||||
|
/* This set of options configures the range of sector size to be supported. (512,
|
||||||
|
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
|
||||||
|
/ harddisk, but a larger value may be required for on-board flash memory and some
|
||||||
|
/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
|
||||||
|
/ for variable sector size mode and disk_ioctl() function needs to implement
|
||||||
|
/ GET_SECTOR_SIZE command. */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_LBA64 0
|
||||||
|
/* This option switches support for 64-bit LBA. (0:Disable or 1:Enable)
|
||||||
|
/ To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_MIN_GPT 0x10000000
|
||||||
|
/* Minimum number of sectors to switch GPT as partitioning format in f_mkfs and
|
||||||
|
/ f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_USE_TRIM 0
|
||||||
|
/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
|
||||||
|
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
|
||||||
|
/ disk_ioctl() function. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ System Configurations
|
||||||
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define FF_FS_TINY 0
|
||||||
|
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||||
|
/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.
|
||||||
|
/ Instead of private sector buffer eliminated from the file object, common sector
|
||||||
|
/ buffer in the filesystem object (FATFS) is used for the file data transfer. */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_FS_EXFAT 0
|
||||||
|
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
|
||||||
|
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
|
||||||
|
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_FS_NORTC 1
|
||||||
|
#define FF_NORTC_MON 1
|
||||||
|
#define FF_NORTC_MDAY 1
|
||||||
|
#define FF_NORTC_YEAR 2020
|
||||||
|
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
|
||||||
|
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
|
||||||
|
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp
|
||||||
|
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
|
||||||
|
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
|
||||||
|
/ added to the project to read current time form real-time clock. FF_NORTC_MON,
|
||||||
|
/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
|
||||||
|
/ These options have no effect in read-only configuration (FF_FS_READONLY = 1). */
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_FS_NOFSINFO 0
|
||||||
|
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
|
||||||
|
/ option, and f_getfree() function at first time after volume mount will force
|
||||||
|
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
|
||||||
|
/
|
||||||
|
/ bit0=0: Use free cluster count in the FSINFO if available.
|
||||||
|
/ bit0=1: Do not trust free cluster count in the FSINFO.
|
||||||
|
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
|
||||||
|
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define FF_FS_LOCK 0
|
||||||
|
/* The option FF_FS_LOCK switches file lock function to control duplicated file open
|
||||||
|
/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY
|
||||||
|
/ is 1.
|
||||||
|
/
|
||||||
|
/ 0: Disable file lock function. To avoid volume corruption, application program
|
||||||
|
/ should avoid illegal open, remove and rename to the open objects.
|
||||||
|
/ >0: Enable file lock function. The value defines how many files/sub-directories
|
||||||
|
/ can be opened simultaneously under file lock control. Note that the file
|
||||||
|
/ lock control is independent of re-entrancy. */
|
||||||
|
|
||||||
|
|
||||||
|
/* #include <somertos.h> // O/S definitions */
|
||||||
|
#define FF_FS_REENTRANT 0
|
||||||
|
#define FF_FS_TIMEOUT 1000
|
||||||
|
#define FF_SYNC_t HANDLE
|
||||||
|
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
|
||||||
|
/ module itself. Note that regardless of this option, file access to different
|
||||||
|
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
|
||||||
|
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
|
||||||
|
/ to the same volume is under control of this function.
|
||||||
|
/
|
||||||
|
/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.
|
||||||
|
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
|
||||||
|
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
|
||||||
|
/ function, must be added to the project. Samples are available in
|
||||||
|
/ option/syscall.c.
|
||||||
|
/
|
||||||
|
/ The FF_FS_TIMEOUT defines timeout period in unit of time tick.
|
||||||
|
/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
|
||||||
|
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
|
||||||
|
/ included somewhere in the scope of ff.h. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--- End of configuration options ---*/
|
170
src/fatfs/ffsystem.c
Normal file
170
src/fatfs/ffsystem.c
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* Sample Code of OS Dependent Functions for FatFs */
|
||||||
|
/* (C)ChaN, 2018 */
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "ff.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* Allocate a memory block */
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
|
||||||
|
UINT msize /* Number of bytes to allocate */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return malloc(msize); /* Allocate a new memory block with POSIX API */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* Free a memory block */
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void ff_memfree (
|
||||||
|
void* mblock /* Pointer to the memory block to free (nothing to do if null) */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
free(mblock); /* Free the memory block with POSIX API */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if FF_FS_REENTRANT /* Mutal exclusion */
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* Create a Synchronization Object */
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* This function is called in f_mount() function to create a new
|
||||||
|
/ synchronization object for the volume, such as semaphore and mutex.
|
||||||
|
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */
|
||||||
|
|
||||||
|
|
||||||
|
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */
|
||||||
|
BYTE vol, /* Corresponding volume (logical drive number) */
|
||||||
|
FF_SYNC_t* sobj /* Pointer to return the created sync object */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* Win32 */
|
||||||
|
*sobj = CreateMutex(NULL, FALSE, NULL);
|
||||||
|
return (int)(*sobj != INVALID_HANDLE_VALUE);
|
||||||
|
|
||||||
|
/* uITRON */
|
||||||
|
// T_CSEM csem = {TA_TPRI,1,1};
|
||||||
|
// *sobj = acre_sem(&csem);
|
||||||
|
// return (int)(*sobj > 0);
|
||||||
|
|
||||||
|
/* uC/OS-II */
|
||||||
|
// OS_ERR err;
|
||||||
|
// *sobj = OSMutexCreate(0, &err);
|
||||||
|
// return (int)(err == OS_NO_ERR);
|
||||||
|
|
||||||
|
/* FreeRTOS */
|
||||||
|
// *sobj = xSemaphoreCreateMutex();
|
||||||
|
// return (int)(*sobj != NULL);
|
||||||
|
|
||||||
|
/* CMSIS-RTOS */
|
||||||
|
// *sobj = osMutexCreate(&Mutex[vol]);
|
||||||
|
// return (int)(*sobj != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* Delete a Synchronization Object */
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* This function is called in f_mount() function to delete a synchronization
|
||||||
|
/ object that created with ff_cre_syncobj() function. When a 0 is returned,
|
||||||
|
/ the f_mount() function fails with FR_INT_ERR.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */
|
||||||
|
FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* Win32 */
|
||||||
|
return (int)CloseHandle(sobj);
|
||||||
|
|
||||||
|
/* uITRON */
|
||||||
|
// return (int)(del_sem(sobj) == E_OK);
|
||||||
|
|
||||||
|
/* uC/OS-II */
|
||||||
|
// OS_ERR err;
|
||||||
|
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err);
|
||||||
|
// return (int)(err == OS_NO_ERR);
|
||||||
|
|
||||||
|
/* FreeRTOS */
|
||||||
|
// vSemaphoreDelete(sobj);
|
||||||
|
// return 1;
|
||||||
|
|
||||||
|
/* CMSIS-RTOS */
|
||||||
|
// return (int)(osMutexDelete(sobj) == osOK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* Request Grant to Access the Volume */
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* This function is called on entering file functions to lock the volume.
|
||||||
|
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
|
||||||
|
FF_SYNC_t sobj /* Sync object to wait */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* Win32 */
|
||||||
|
return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0);
|
||||||
|
|
||||||
|
/* uITRON */
|
||||||
|
// return (int)(wai_sem(sobj) == E_OK);
|
||||||
|
|
||||||
|
/* uC/OS-II */
|
||||||
|
// OS_ERR err;
|
||||||
|
// OSMutexPend(sobj, FF_FS_TIMEOUT, &err));
|
||||||
|
// return (int)(err == OS_NO_ERR);
|
||||||
|
|
||||||
|
/* FreeRTOS */
|
||||||
|
// return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);
|
||||||
|
|
||||||
|
/* CMSIS-RTOS */
|
||||||
|
// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* Release Grant to Access the Volume */
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* This function is called on leaving file functions to unlock the volume.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ff_rel_grant (
|
||||||
|
FF_SYNC_t sobj /* Sync object to be signaled */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* Win32 */
|
||||||
|
ReleaseMutex(sobj);
|
||||||
|
|
||||||
|
/* uITRON */
|
||||||
|
// sig_sem(sobj);
|
||||||
|
|
||||||
|
/* uC/OS-II */
|
||||||
|
// OSMutexPost(sobj);
|
||||||
|
|
||||||
|
/* FreeRTOS */
|
||||||
|
// xSemaphoreGive(sobj);
|
||||||
|
|
||||||
|
/* CMSIS-RTOS */
|
||||||
|
// osMutexRelease(sobj);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
15593
src/fatfs/ffunicode.c
Normal file
15593
src/fatfs/ffunicode.c
Normal file
File diff suppressed because it is too large
Load diff
136
src/include/A2560K/VICKYIII_a2560k.h
Normal file
136
src/include/A2560K/VICKYIII_a2560k.h
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* Registers and memory blocks for VICKY III for the A2560K
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VICKYIII_General_H
|
||||||
|
#define __VICKYIII_General_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Screen Channel A
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MasterControlReg_A ((volatile unsigned long *)0xFEC40000)
|
||||||
|
#define VKY3_MCR_TEXT_EN 0x00000001 /* Text Mode Enable */
|
||||||
|
#define VKY3_MCR_TEXT_OVRLY 0x00000002 /* Text Mode overlay */
|
||||||
|
#define VKY3_MCR_GRAPH_EN 0x00000004 /* Graphic Mode Enable */
|
||||||
|
#define VKY3_MCR_BITMAP_EN 0x00000008 /* Bitmap Engine Enable */
|
||||||
|
#define VKY3_MCR_VIDEO_DISABLE 0x00000080 /* Disable the video engine and VRAM access by Vicky */
|
||||||
|
#define VKY3_MCR_RESOLUTION_MASK 0x00000300 /* Resolution - 00: 640x480, 01:800x600, 10: 1024x768, 11: 640x400 */
|
||||||
|
#define VKY3_MCR_640x480 0x00000000
|
||||||
|
#define VKY3_MCR_800x600 0x00000100
|
||||||
|
#define VKY3_MCR_1024x768 0x00000200
|
||||||
|
#define VKY3_MCR_640x400 0x00000300
|
||||||
|
#define VKY3_MCRA_1024x768 0x00000800
|
||||||
|
#define VKY3_MCR_DOUBLE_EN 0x00000400 /* Doubling Pixel */
|
||||||
|
#define VKY3_MCR_GAMMA_EN 0x00010000 /* GAMMA Enable */
|
||||||
|
#define VKY3_MCR_MANUAL_GAMMA_EN 0x00020000 /* Enable Manual GAMMA Enable */
|
||||||
|
#define VKY3_MCR_DISABLE_SYNC 0x00040000 /* Turn OFF sync (to monitor in sleep mode) */
|
||||||
|
|
||||||
|
|
||||||
|
/* Access to DIP switch information (read only) */
|
||||||
|
#define VKY3_DIP_REG ((volatile unsigned short *)0xFEC40002)
|
||||||
|
/* Bits 0 - 12: Master Control Register data */
|
||||||
|
#define VKY3_DIP_GAMMA 0x2000 /* DIP switch indication for Gamma correction */
|
||||||
|
#define VKY3_DIP_HIRES 0x4000 /* DIP switch for high resolution mode */
|
||||||
|
#define VKY3_PLL_ACTIVE_CLK 0x8000 /* Active Clock --- 0: 25.175Mhz, 1: 40Mhz */
|
||||||
|
|
||||||
|
#define BorderControlReg_L_A ((volatile unsigned long *)0xFEC40004)
|
||||||
|
#define VKY3_BRDR_EN 0x00000001 /* Border Enable */
|
||||||
|
#define VKY3_X_SCROLL_MASK 0x00000070 /* X Scroll */
|
||||||
|
#define VKY3_X_SIZE_MASK 0x00003f00 /* X Size */
|
||||||
|
#define VKY3_Y_SIZE_MASK 0x003f0000 /* Y Size */
|
||||||
|
|
||||||
|
#define BorderControlReg_H_A ((volatile unsigned long *)0xFEC40008)
|
||||||
|
#define BackGroundControlReg_A ((volatile unsigned long *)0xFEC4000C)
|
||||||
|
#define CursorControlReg_L_A ((volatile unsigned long *)0xFEC40010)
|
||||||
|
#define CursorControlReg_H_A ((volatile unsigned long *)0xFEC40014)
|
||||||
|
|
||||||
|
#define LineInterrupt0_A ((volatile unsigned long *)0xFEC40018)
|
||||||
|
#define LineInterrupt1_A ((volatile unsigned long *)0xFEC4001A)
|
||||||
|
#define LineInterrupt2_A ((volatile unsigned long *)0xFEC4001C)
|
||||||
|
#define LineInterrupt3_A ((volatile unsigned long *)0xFEC4001E)
|
||||||
|
|
||||||
|
#define FONT_Size_Ctrl_A ((volatile unsigned long *)0xFEC40020)
|
||||||
|
#define FONT_Count_Ctrl_A ((volatile unsigned long *)0xFEC40024)
|
||||||
|
|
||||||
|
#define MousePointer_Mem_A ((volatile unsigned long *)0xFEC40400)
|
||||||
|
#define MousePtr_A_CTRL_Reg ((volatile unsigned long *)0xFEC40C00)
|
||||||
|
#define MousePtr_En 0x0001
|
||||||
|
|
||||||
|
#define MousePtr_A_X_Pos ((volatile unsigned long *)0xFEC40C02)
|
||||||
|
#define MousePtr_A_Y_Pos ((volatile unsigned long *)0xFEC40C04)
|
||||||
|
#define MousePtr_A_Mouse0 ((volatile unsigned long *)0xFEC40C0A)
|
||||||
|
#define MousePtr_A_Mouse1 ((volatile unsigned long *)0xFEC40C0C)
|
||||||
|
#define MousePtr_A_Mouse2 ((volatile unsigned long *)0xFEC40C0E)
|
||||||
|
|
||||||
|
#define ScreenText_A ((volatile char *)0xFEC60000) /* Text matrix */
|
||||||
|
#define ColorText_A ((volatile uint8_t *)0xFEC68000) /* Color matrix */
|
||||||
|
#define FG_CLUT_A ((volatile unsigned long *)0xFEC6C400) /* Foreground LUT */
|
||||||
|
#define BG_CLUT_A ((volatile unsigned long *)0xFEC6C440) /* Background LUT */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Screen Channel B
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MasterControlReg_B ((volatile unsigned long *)0xFEC80000)
|
||||||
|
#define BorderControlReg_L_B ((volatile unsigned long *)0xFEC80004)
|
||||||
|
#define BorderControlReg_H_B ((volatile unsigned long *)0xFEC80008)
|
||||||
|
#define BackGroundControlReg_B ((volatile unsigned long *)0xFEC8000C)
|
||||||
|
#define CursorControlReg_L_B ((volatile unsigned long *)0xFEC80010)
|
||||||
|
#define CursorControlReg_H_B ((volatile unsigned long *)0xFEC80014)
|
||||||
|
|
||||||
|
#define LineInterrupt0_B ((volatile unsigned long *)0xFEC80018)
|
||||||
|
#define LineInterrupt1_B ((volatile unsigned long *)0xFEC8001A)
|
||||||
|
#define LineInterrupt2_B ((volatile unsigned long *)0xFEC8001C)
|
||||||
|
#define LineInterrupt3_B ((volatile unsigned long *)0xFEC8001E)
|
||||||
|
|
||||||
|
#define MousePointer_Mem_B ((volatile unsigned long *)0xFEC80400)
|
||||||
|
#define MousePtr_B_CTRL_Reg ((volatile unsigned long *)0xFEC80C00)
|
||||||
|
|
||||||
|
#define MousePtr_B_X_Pos ((volatile unsigned long *)0xFEC80C02)
|
||||||
|
#define MousePtr_B_Y_Pos ((volatile unsigned long *)0xFEC80C04)
|
||||||
|
#define MousePtr_B_Mouse0 ((volatile unsigned long *)0xFEC80C0A)
|
||||||
|
#define MousePtr_B_Mouse1 ((volatile unsigned long *)0xFEC80C0C)
|
||||||
|
#define MousePtr_B_Mouse2 ((volatile unsigned long *)0xFEC80C0E)
|
||||||
|
|
||||||
|
#define ScreenText_B ((volatile char *)0xFECA0000) /* Text matrix */
|
||||||
|
#define ColorText_B ((volatile uint8_t *)0xFECA8000) /* Color matrix */
|
||||||
|
#define FG_CLUT_B ((volatile unsigned long *)0xFECAC400) /* Foreground LUT */
|
||||||
|
#define BG_CLUT_B ((volatile unsigned long *)0xFECAC440) /* Background LUT */
|
||||||
|
|
||||||
|
#define BM0_Control_Reg ((volatile unsigned long *)0xFEC80100)
|
||||||
|
#define BM0_Addy_Pointer_Reg ((volatile unsigned long *)0xFEC80104)
|
||||||
|
|
||||||
|
#define Sprite_0_CTRL ((volatile unsigned long *)0xFEC81000)
|
||||||
|
#define Sprite_0_ADDY_HI ((volatile unsigned long *)0xFEC81002)
|
||||||
|
#define Sprite_0_POS_X ((volatile unsigned long *)0xFEC81004)
|
||||||
|
#define Sprite_0_POS_Y ((volatile unsigned long *)0xFEC81006)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Color lookup tables
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LUT_0 ((volatile uint8_t *)0xFEC82000)
|
||||||
|
#define LUT_1 ((volatile uint8_t *)0xFEC82400)
|
||||||
|
#define LUT_2 ((volatile uint8_t *)0xFEC82800)
|
||||||
|
#define LUT_3 ((volatile uint8_t *)0xFEC82C00)
|
||||||
|
#define LUT_4 ((volatile uint8_t *)0xFEC83000)
|
||||||
|
#define LUT_5 ((volatile uint8_t *)0xFEC83400)
|
||||||
|
#define LUT_6 ((volatile uint8_t *)0xFEC83800)
|
||||||
|
#define LUT_7 ((volatile uint8_t *)0xFEC83C00)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Text mode font memory
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define VICKY_TXT_FONT_A ((volatile unsigned char *)0xFEC48000) /* $00C48000..$00C48FFF - FONT MEMORY Channel A */
|
||||||
|
#define VICKY_TXT_FONT_B ((volatile unsigned char *)0xFEC88000) /* $00C88000..$00C88FFF - FONT MEMORY Channel B */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Location of VRAM
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define VRAM_Bank0 ((volatile uint8_t *)0x00800000)
|
||||||
|
#define VRAM_Bank1 ((volatile uint8_t *)0x00A00000)
|
||||||
|
|
||||||
|
#endif
|
496
src/include/A2560K/YM2151.h
Normal file
496
src/include/A2560K/YM2151.h
Normal file
|
@ -0,0 +1,496 @@
|
||||||
|
#ifndef YM2151_H_ /* Include guard */
|
||||||
|
#define YM2151_H_
|
||||||
|
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
// External OPM
|
||||||
|
unsigned char * EXT_OPM_01_TEST = (void *) 0xFEC20601;
|
||||||
|
unsigned char * EXT_OPM_08_KEY_ON_OFF = (void *) 0xFEC20608;
|
||||||
|
unsigned char * EXT_OPM_0F_NE_NFREQ = (void *) 0xFEC2060F;
|
||||||
|
unsigned char * EXT_OPM_10_CLK_A1 = (void *) 0xFEC20610;
|
||||||
|
unsigned char * EXT_OPM_11_CLK_A2 = (void *) 0xFEC20611;
|
||||||
|
unsigned char * EXT_OPM_12_CLK_B = (void *) 0xFEC20612;
|
||||||
|
unsigned char * EXT_OPM_14_CMS_FLAG_RST_IRQEN_LD = (void *) 0xFEC20614;
|
||||||
|
unsigned char * EXT_OPM_18_LFRQ = (void *) 0xFEC20618;
|
||||||
|
unsigned char * EXT_OPM_19_PMD_AMD = (void *) 0xFEC20619;
|
||||||
|
unsigned char * EXT_OPM_1B_CT_W = (void *) 0xFEC2061B;
|
||||||
|
|
||||||
|
unsigned char * EXT_OPM_20_A_RL_FR_CONNECT = (void *) 0xFEC20620;
|
||||||
|
unsigned char * EXT_OPM_21_B_RL_FR_CONNECT = (void *) 0xFEC20621;
|
||||||
|
unsigned char * EXT_OPM_22_C_RL_FR_CONNECT = (void *) 0xFEC20622;
|
||||||
|
unsigned char * EXT_OPM_23_D_RL_FR_CONNECT = (void *) 0xFEC20623;
|
||||||
|
unsigned char * EXT_OPM_24_E_RL_FR_CONNECT = (void *) 0xFEC20624;
|
||||||
|
unsigned char * EXT_OPM_25_F_RL_FR_CONNECT = (void *) 0xFEC20625;
|
||||||
|
unsigned char * EXT_OPM_26_G_RL_FR_CONNECT = (void *) 0xFEC20626;
|
||||||
|
unsigned char * EXT_OPM_27_H_RL_FR_CONNECT = (void *) 0xFEC20627;
|
||||||
|
unsigned char * EXT_OPM_28_A_KC = (void *) 0xFEC20628;
|
||||||
|
unsigned char * EXT_OPM_29_B_KC = (void *) 0xFEC20629;
|
||||||
|
unsigned char * EXT_OPM_2A_C_KC = (void *) 0xFEC2062A;
|
||||||
|
unsigned char * EXT_OPM_2B_D_KC = (void *) 0xFEC2062B;
|
||||||
|
unsigned char * EXT_OPM_2C_E_KC = (void *) 0xFEC2062C;
|
||||||
|
unsigned char * EXT_OPM_2D_F_KC = (void *) 0xFEC2062D;
|
||||||
|
unsigned char * EXT_OPM_2E_G_KC = (void *) 0xFEC2062E;
|
||||||
|
unsigned char * EXT_OPM_2F_H_KC = (void *) 0xFEC2062F;
|
||||||
|
unsigned char * EXT_OPM_30_A_KF = (void *) 0xFEC20630;
|
||||||
|
unsigned char * EXT_OPM_31_B_KF = (void *) 0xFEC20631;
|
||||||
|
unsigned char * EXT_OPM_32_C_KF = (void *) 0xFEC20632;
|
||||||
|
unsigned char * EXT_OPM_33_D_KF = (void *) 0xFEC20633;
|
||||||
|
unsigned char * EXT_OPM_34_E_KF = (void *) 0xFEC20634;
|
||||||
|
unsigned char * EXT_OPM_35_F_KF = (void *) 0xFEC20635;
|
||||||
|
unsigned char * EXT_OPM_36_G_KF = (void *) 0xFEC20636;
|
||||||
|
unsigned char * EXT_OPM_37_H_KF = (void *) 0xFEC20637;
|
||||||
|
unsigned char * EXT_OPM_38_A_PMS_AMS = (void *) 0xFEC20638;
|
||||||
|
unsigned char * EXT_OPM_39_B_PMS_AMS = (void *) 0xFEC20639;
|
||||||
|
unsigned char * EXT_OPM_3A_C_PMS_AMS = (void *) 0xFEC2063A;
|
||||||
|
unsigned char * EXT_OPM_3B_D_PMS_AMS = (void *) 0xFEC2063B;
|
||||||
|
unsigned char * EXT_OPM_3C_E_PMS_AMS = (void *) 0xFEC2063C;
|
||||||
|
unsigned char * EXT_OPM_3D_F_PMS_AMS = (void *) 0xFEC2063D;
|
||||||
|
unsigned char * EXT_OPM_3E_G_PMS_AMS = (void *) 0xFEC2063E;
|
||||||
|
unsigned char * EXT_OPM_3F_H_PMS_AMS = (void *) 0xFEC2063F;
|
||||||
|
unsigned char * EXT_OPM_40_A_M1_DT1_MUL = (void *) 0xFEC20640;
|
||||||
|
unsigned char * EXT_OPM_41_B_M1_DT1_MUL = (void *) 0xFEC20641;
|
||||||
|
unsigned char * EXT_OPM_42_C_M1_DT1_MUL = (void *) 0xFEC20642;
|
||||||
|
unsigned char * EXT_OPM_43_D_M1_DT1_MUL = (void *) 0xFEC20643;
|
||||||
|
unsigned char * EXT_OPM_44_E_M1_DT1_MUL = (void *) 0xFEC20644;
|
||||||
|
unsigned char * EXT_OPM_45_F_M1_DT1_MUL = (void *) 0xFEC20645;
|
||||||
|
unsigned char * EXT_OPM_46_G_M1_DT1_MUL = (void *) 0xFEC20646;
|
||||||
|
unsigned char * EXT_OPM_47_H_M1_DT1_MUL = (void *) 0xFEC20647;
|
||||||
|
unsigned char * EXT_OPM_48_A_M2_DT1_MUL = (void *) 0xFEC20648;
|
||||||
|
unsigned char * EXT_OPM_49_B_M2_DT1_MUL = (void *) 0xFEC20649;
|
||||||
|
unsigned char * EXT_OPM_4A_C_M2_DT1_MUL = (void *) 0xFEC2064A;
|
||||||
|
unsigned char * EXT_OPM_4B_D_M2_DT1_MUL = (void *) 0xFEC2064B;
|
||||||
|
unsigned char * EXT_OPM_4C_E_M2_DT1_MUL = (void *) 0xFEC2064C;
|
||||||
|
unsigned char * EXT_OPM_4D_F_M2_DT1_MUL = (void *) 0xFEC2064D;
|
||||||
|
unsigned char * EXT_OPM_4E_G_M2_DT1_MUL = (void *) 0xFEC2064E;
|
||||||
|
unsigned char * EXT_OPM_4F_H_M2_DT1_MUL = (void *) 0xFEC2064F;
|
||||||
|
unsigned char * EXT_OPM_50_A_C1_DT1_MUL = (void *) 0xFEC20650;
|
||||||
|
unsigned char * EXT_OPM_51_B_C1_DT1_MUL = (void *) 0xFEC20651;
|
||||||
|
unsigned char * EXT_OPM_52_C_C1_DT1_MUL = (void *) 0xFEC20652;
|
||||||
|
unsigned char * EXT_OPM_53_D_C1_DT1_MUL = (void *) 0xFEC20653;
|
||||||
|
unsigned char * EXT_OPM_54_E_C1_DT1_MUL = (void *) 0xFEC20654;
|
||||||
|
unsigned char * EXT_OPM_55_F_C1_DT1_MUL = (void *) 0xFEC20655;
|
||||||
|
unsigned char * EXT_OPM_56_G_C1_DT1_MUL = (void *) 0xFEC20656;
|
||||||
|
unsigned char * EXT_OPM_57_H_C1_DT1_MUL = (void *) 0xFEC20657;
|
||||||
|
unsigned char * EXT_OPM_58_A_C2_DT1_MUL = (void *) 0xFEC20658;
|
||||||
|
unsigned char * EXT_OPM_59_B_C2_DT1_MUL = (void *) 0xFEC20659;
|
||||||
|
unsigned char * EXT_OPM_5A_C_C2_DT1_MUL = (void *) 0xFEC2065A;
|
||||||
|
unsigned char * EXT_OPM_5B_D_C2_DT1_MUL = (void *) 0xFEC2065B;
|
||||||
|
unsigned char * EXT_OPM_5C_E_C2_DT1_MUL = (void *) 0xFEC2065C;
|
||||||
|
unsigned char * EXT_OPM_5D_F_C2_DT1_MUL = (void *) 0xFEC2065D;
|
||||||
|
unsigned char * EXT_OPM_5E_G_C2_DT1_MUL = (void *) 0xFEC2065E;
|
||||||
|
unsigned char * EXT_OPM_5F_H_C2_DT1_MUL = (void *) 0xFEC2065F;
|
||||||
|
unsigned char * EXT_OPM_60_A_M1_TL = (void *) 0xFEC20660;
|
||||||
|
unsigned char * EXT_OPM_61_B_M1_TL = (void *) 0xFEC20661;
|
||||||
|
unsigned char * EXT_OPM_62_C_M1_TL = (void *) 0xFEC20662;
|
||||||
|
unsigned char * EXT_OPM_63_D_M1_TL = (void *) 0xFEC20663;
|
||||||
|
unsigned char * EXT_OPM_64_E_M1_TL = (void *) 0xFEC20664;
|
||||||
|
unsigned char * EXT_OPM_65_F_M1_TL = (void *) 0xFEC20665;
|
||||||
|
unsigned char * EXT_OPM_66_G_M1_TL = (void *) 0xFEC20666;
|
||||||
|
unsigned char * EXT_OPM_67_H_M1_TL = (void *) 0xFEC20667;
|
||||||
|
unsigned char * EXT_OPM_68_A_M2_TL = (void *) 0xFEC20668;
|
||||||
|
unsigned char * EXT_OPM_69_B_M2_TL = (void *) 0xFEC20669;
|
||||||
|
unsigned char * EXT_OPM_6A_C_M2_TL = (void *) 0xFEC2066A;
|
||||||
|
unsigned char * EXT_OPM_6B_D_M2_TL = (void *) 0xFEC2066B;
|
||||||
|
unsigned char * EXT_OPM_6C_E_M2_TL = (void *) 0xFEC2066C;
|
||||||
|
unsigned char * EXT_OPM_6D_F_M2_TL = (void *) 0xFEC2066D;
|
||||||
|
unsigned char * EXT_OPM_6E_G_M2_TL = (void *) 0xFEC2066E;
|
||||||
|
unsigned char * EXT_OPM_6F_H_M2_TL = (void *) 0xFEC2066F;
|
||||||
|
unsigned char * EXT_OPM_70_A_C1_TL = (void *) 0xFEC20670;
|
||||||
|
unsigned char * EXT_OPM_71_B_C1_TL = (void *) 0xFEC20671;
|
||||||
|
unsigned char * EXT_OPM_72_C_C1_TL = (void *) 0xFEC20672;
|
||||||
|
unsigned char * EXT_OPM_73_D_C1_TL = (void *) 0xFEC20673;
|
||||||
|
unsigned char * EXT_OPM_74_E_C1_TL = (void *) 0xFEC20674;
|
||||||
|
unsigned char * EXT_OPM_75_F_C1_TL = (void *) 0xFEC20675;
|
||||||
|
unsigned char * EXT_OPM_76_G_C1_TL = (void *) 0xFEC20676;
|
||||||
|
unsigned char * EXT_OPM_77_H_C1_TL = (void *) 0xFEC20677;
|
||||||
|
unsigned char * EXT_OPM_78_A_C2_TL = (void *) 0xFEC20678;
|
||||||
|
unsigned char * EXT_OPM_79_B_C2_TL = (void *) 0xFEC20679;
|
||||||
|
unsigned char * EXT_OPM_7A_C_C2_TL = (void *) 0xFEC2067A;
|
||||||
|
unsigned char * EXT_OPM_7B_D_C2_TL = (void *) 0xFEC2067B;
|
||||||
|
unsigned char * EXT_OPM_7C_E_C2_TL = (void *) 0xFEC2067C;
|
||||||
|
unsigned char * EXT_OPM_7D_F_C2_TL = (void *) 0xFEC2067D;
|
||||||
|
unsigned char * EXT_OPM_7E_G_C2_TL = (void *) 0xFEC2067E;
|
||||||
|
unsigned char * EXT_OPM_7F_H_C2_TL = (void *) 0xFEC2067F;
|
||||||
|
unsigned char * EXT_OPM_80_A_M1_KS_AR = (void *) 0xFEC20680;
|
||||||
|
unsigned char * EXT_OPM_81_B_M1_KS_AR = (void *) 0xFEC20681;
|
||||||
|
unsigned char * EXT_OPM_82_C_M1_KS_AR = (void *) 0xFEC20682;
|
||||||
|
unsigned char * EXT_OPM_83_D_M1_KS_AR = (void *) 0xFEC20683;
|
||||||
|
unsigned char * EXT_OPM_84_E_M1_KS_AR = (void *) 0xFEC20684;
|
||||||
|
unsigned char * EXT_OPM_85_F_M1_KS_AR = (void *) 0xFEC20685;
|
||||||
|
unsigned char * EXT_OPM_86_G_M1_KS_AR = (void *) 0xFEC20686;
|
||||||
|
unsigned char * EXT_OPM_87_H_M1_KS_AR = (void *) 0xFEC20687;
|
||||||
|
unsigned char * EXT_OPM_88_A_M2_KS_AR = (void *) 0xFEC20688;
|
||||||
|
unsigned char * EXT_OPM_89_B_M2_KS_AR = (void *) 0xFEC20689;
|
||||||
|
unsigned char * EXT_OPM_8A_C_M2_KS_AR = (void *) 0xFEC2068A;
|
||||||
|
unsigned char * EXT_OPM_8B_D_M2_KS_AR = (void *) 0xFEC2068B;
|
||||||
|
unsigned char * EXT_OPM_8C_E_M2_KS_AR = (void *) 0xFEC2068C;
|
||||||
|
unsigned char * EXT_OPM_8D_F_M2_KS_AR = (void *) 0xFEC2068D;
|
||||||
|
unsigned char * EXT_OPM_8E_G_M2_KS_AR = (void *) 0xFEC2068E;
|
||||||
|
unsigned char * EXT_OPM_8F_H_M2_KS_AR = (void *) 0xFEC2068F;
|
||||||
|
unsigned char * EXT_OPM_90_A_C1_KS_AR = (void *) 0xFEC20690;
|
||||||
|
unsigned char * EXT_OPM_91_B_C1_KS_AR = (void *) 0xFEC20691;
|
||||||
|
unsigned char * EXT_OPM_92_C_C1_KS_AR = (void *) 0xFEC20692;
|
||||||
|
unsigned char * EXT_OPM_93_D_C1_KS_AR = (void *) 0xFEC20693;
|
||||||
|
unsigned char * EXT_OPM_94_E_C1_KS_AR = (void *) 0xFEC20694;
|
||||||
|
unsigned char * EXT_OPM_95_F_C1_KS_AR = (void *) 0xFEC20695;
|
||||||
|
unsigned char * EXT_OPM_96_G_C1_KS_AR = (void *) 0xFEC20696;
|
||||||
|
unsigned char * EXT_OPM_97_H_C1_KS_AR = (void *) 0xFEC20697;
|
||||||
|
unsigned char * EXT_OPM_98_A_C2_KS_AR = (void *) 0xFEC20698;
|
||||||
|
unsigned char * EXT_OPM_99_B_C2_KS_AR = (void *) 0xFEC20699;
|
||||||
|
unsigned char * EXT_OPM_9A_C_C2_KS_AR = (void *) 0xFEC2069A;
|
||||||
|
unsigned char * EXT_OPM_9B_D_C2_KS_AR = (void *) 0xFEC2069B;
|
||||||
|
unsigned char * EXT_OPM_9C_E_C2_KS_AR = (void *) 0xFEC2069C;
|
||||||
|
unsigned char * EXT_OPM_9D_F_C2_KS_AR = (void *) 0xFEC2069D;
|
||||||
|
unsigned char * EXT_OPM_9E_G_C2_KS_AR = (void *) 0xFEC2069E;
|
||||||
|
unsigned char * EXT_OPM_9F_H_C2_KS_AR = (void *) 0xFEC2069F;
|
||||||
|
unsigned char * EXT_OPM_A0_A_M1_AMS_EN_D1R = (void *) 0xFEC206A0;
|
||||||
|
unsigned char * EXT_OPM_A1_B_M1_AMS_EN_D1R = (void *) 0xFEC206A1;
|
||||||
|
unsigned char * EXT_OPM_A2_C_M1_AMS_EN_D1R = (void *) 0xFEC206A2;
|
||||||
|
unsigned char * EXT_OPM_A3_D_M1_AMS_EN_D1R = (void *) 0xFEC206A3;
|
||||||
|
unsigned char * EXT_OPM_A4_E_M1_AMS_EN_D1R = (void *) 0xFEC206A4;
|
||||||
|
unsigned char * EXT_OPM_A5_F_M1_AMS_EN_D1R = (void *) 0xFEC206A5;
|
||||||
|
unsigned char * EXT_OPM_A6_G_M1_AMS_EN_D1R = (void *) 0xFEC206A6;
|
||||||
|
unsigned char * EXT_OPM_A7_H_M1_AMS_EN_D1R = (void *) 0xFEC206A7;
|
||||||
|
unsigned char * EXT_OPM_A8_A_M2_AMS_EN_D1R = (void *) 0xFEC206A8;
|
||||||
|
unsigned char * EXT_OPM_A9_B_M2_AMS_EN_D1R = (void *) 0xFEC206A9;
|
||||||
|
unsigned char * EXT_OPM_AA_C_M2_AMS_EN_D1R = (void *) 0xFEC206AA;
|
||||||
|
unsigned char * EXT_OPM_AB_D_M2_AMS_EN_D1R = (void *) 0xFEC206AB;
|
||||||
|
unsigned char * EXT_OPM_AC_E_M2_AMS_EN_D1R = (void *) 0xFEC206AC;
|
||||||
|
unsigned char * EXT_OPM_AD_F_M2_AMS_EN_D1R = (void *) 0xFEC206AD;
|
||||||
|
unsigned char * EXT_OPM_AE_G_M2_AMS_EN_D1R = (void *) 0xFEC206AE;
|
||||||
|
unsigned char * EXT_OPM_AF_H_M2_AMS_EN_D1R = (void *) 0xFEC206AF;
|
||||||
|
unsigned char * EXT_OPM_B0_A_C1_AMS_EN_D1R = (void *) 0xFEC206B0;
|
||||||
|
unsigned char * EXT_OPM_B1_B_C1_AMS_EN_D1R = (void *) 0xFEC206B1;
|
||||||
|
unsigned char * EXT_OPM_B2_C_C1_AMS_EN_D1R = (void *) 0xFEC206B2;
|
||||||
|
unsigned char * EXT_OPM_B3_D_C1_AMS_EN_D1R = (void *) 0xFEC206B3;
|
||||||
|
unsigned char * EXT_OPM_B4_E_C1_AMS_EN_D1R = (void *) 0xFEC206B4;
|
||||||
|
unsigned char * EXT_OPM_B5_F_C1_AMS_EN_D1R = (void *) 0xFEC206B5;
|
||||||
|
unsigned char * EXT_OPM_B6_G_C1_AMS_EN_D1R = (void *) 0xFEC206B6;
|
||||||
|
unsigned char * EXT_OPM_B7_H_C1_AMS_EN_D1R = (void *) 0xFEC206B7;
|
||||||
|
unsigned char * EXT_OPM_B8_A_C2_AMS_EN_D1R = (void *) 0xFEC206B8;
|
||||||
|
unsigned char * EXT_OPM_B9_B_C2_AMS_EN_D1R = (void *) 0xFEC206B9;
|
||||||
|
unsigned char * EXT_OPM_BA_C_C2_AMS_EN_D1R = (void *) 0xFEC206BA;
|
||||||
|
unsigned char * EXT_OPM_BB_D_C2_AMS_EN_D1R = (void *) 0xFEC206BB;
|
||||||
|
unsigned char * EXT_OPM_BC_E_C2_AMS_EN_D1R = (void *) 0xFEC206BC;
|
||||||
|
unsigned char * EXT_OPM_BD_F_C2_AMS_EN_D1R = (void *) 0xFEC206BD;
|
||||||
|
unsigned char * EXT_OPM_BE_G_C2_AMS_EN_D1R = (void *) 0xFEC206BE;
|
||||||
|
unsigned char * EXT_OPM_BF_H_C2_AMS_EN_D1R = (void *) 0xFEC206BF;
|
||||||
|
unsigned char * EXT_OPM_C0_A_M1_DT2_D2R = (void *) 0xFEC206C0;
|
||||||
|
unsigned char * EXT_OPM_C1_B_M1_DT2_D2R = (void *) 0xFEC206C1;
|
||||||
|
unsigned char * EXT_OPM_C2_C_M1_DT2_D2R = (void *) 0xFEC206C2;
|
||||||
|
unsigned char * EXT_OPM_C3_D_M1_DT2_D2R = (void *) 0xFEC206C3;
|
||||||
|
unsigned char * EXT_OPM_C4_E_M1_DT2_D2R = (void *) 0xFEC206C4;
|
||||||
|
unsigned char * EXT_OPM_C5_F_M1_DT2_D2R = (void *) 0xFEC206C5;
|
||||||
|
unsigned char * EXT_OPM_C6_G_M1_DT2_D2R = (void *) 0xFEC206C6;
|
||||||
|
unsigned char * EXT_OPM_C7_H_M1_DT2_D2R = (void *) 0xFEC206C7;
|
||||||
|
unsigned char * EXT_OPM_C8_A_M2_DT2_D2R = (void *) 0xFEC206C8;
|
||||||
|
unsigned char * EXT_OPM_C9_B_M2_DT2_D2R = (void *) 0xFEC206C9;
|
||||||
|
unsigned char * EXT_OPM_CA_C_M2_DT2_D2R = (void *) 0xFEC206CA;
|
||||||
|
unsigned char * EXT_OPM_CB_D_M2_DT2_D2R = (void *) 0xFEC206CB;
|
||||||
|
unsigned char * EXT_OPM_CC_E_M2_DT2_D2R = (void *) 0xFEC206CC;
|
||||||
|
unsigned char * EXT_OPM_CD_F_M2_DT2_D2R = (void *) 0xFEC206CD;
|
||||||
|
unsigned char * EXT_OPM_CE_G_M2_DT2_D2R = (void *) 0xFEC206CE;
|
||||||
|
unsigned char * EXT_OPM_CF_H_M2_DT2_D2R = (void *) 0xFEC206CF;
|
||||||
|
unsigned char * EXT_OPM_D0_A_C1_DT2_D2R = (void *) 0xFEC206D0;
|
||||||
|
unsigned char * EXT_OPM_D1_B_C1_DT2_D2R = (void *) 0xFEC206D1;
|
||||||
|
unsigned char * EXT_OPM_D2_C_C1_DT2_D2R = (void *) 0xFEC206D2;
|
||||||
|
unsigned char * EXT_OPM_D3_D_C1_DT2_D2R = (void *) 0xFEC206D3;
|
||||||
|
unsigned char * EXT_OPM_D4_E_C1_DT2_D2R = (void *) 0xFEC206D4;
|
||||||
|
unsigned char * EXT_OPM_D5_F_C1_DT2_D2R = (void *) 0xFEC206D5;
|
||||||
|
unsigned char * EXT_OPM_D6_G_C1_DT2_D2R = (void *) 0xFEC206D6;
|
||||||
|
unsigned char * EXT_OPM_D7_H_C1_DT2_D2R = (void *) 0xFEC206D7;
|
||||||
|
unsigned char * EXT_OPM_D8_A_C2_DT2_D2R = (void *) 0xFEC206D8;
|
||||||
|
unsigned char * EXT_OPM_D9_B_C2_DT2_D2R = (void *) 0xFEC206D9;
|
||||||
|
unsigned char * EXT_OPM_DA_C_C2_DT2_D2R = (void *) 0xFEC206DA;
|
||||||
|
unsigned char * EXT_OPM_DB_D_C2_DT2_D2R = (void *) 0xFEC206DB;
|
||||||
|
unsigned char * EXT_OPM_DC_E_C2_DT2_D2R = (void *) 0xFEC206DC;
|
||||||
|
unsigned char * EXT_OPM_DD_F_C2_DT2_D2R = (void *) 0xFEC206DD;
|
||||||
|
unsigned char * EXT_OPM_DE_G_C2_DT2_D2R = (void *) 0xFEC206DE;
|
||||||
|
unsigned char * EXT_OPM_DF_H_C2_DT2_D2R = (void *) 0xFEC206DF;
|
||||||
|
unsigned char * EXT_OPM_E0_A_M1_D1L_RR = (void *) 0xFEC206E0;
|
||||||
|
unsigned char * EXT_OPM_E1_B_M1_D1L_RR = (void *) 0xFEC206E1;
|
||||||
|
unsigned char * EXT_OPM_E2_C_M1_D1L_RR = (void *) 0xFEC206E2;
|
||||||
|
unsigned char * EXT_OPM_E3_D_M1_D1L_RR = (void *) 0xFEC206E3;
|
||||||
|
unsigned char * EXT_OPM_E4_E_M1_D1L_RR = (void *) 0xFEC206E4;
|
||||||
|
unsigned char * EXT_OPM_E5_F_M1_D1L_RR = (void *) 0xFEC206E5;
|
||||||
|
unsigned char * EXT_OPM_E6_G_M1_D1L_RR = (void *) 0xFEC206E6;
|
||||||
|
unsigned char * EXT_OPM_E7_H_M1_D1L_RR = (void *) 0xFEC206E7;
|
||||||
|
unsigned char * EXT_OPM_E8_A_M2_D1L_RR = (void *) 0xFEC206E8;
|
||||||
|
unsigned char * EXT_OPM_E9_B_M2_D1L_RR = (void *) 0xFEC206E9;
|
||||||
|
unsigned char * EXT_OPM_EA_C_M2_D1L_RR = (void *) 0xFEC206EA;
|
||||||
|
unsigned char * EXT_OPM_EB_D_M2_D1L_RR = (void *) 0xFEC206EB;
|
||||||
|
unsigned char * EXT_OPM_EC_E_M2_D1L_RR = (void *) 0xFEC206EC;
|
||||||
|
unsigned char * EXT_OPM_ED_F_M2_D1L_RR = (void *) 0xFEC206ED;
|
||||||
|
unsigned char * EXT_OPM_EE_G_M2_D1L_RR = (void *) 0xFEC206EE;
|
||||||
|
unsigned char * EXT_OPM_EF_H_M2_D1L_RR = (void *) 0xFEC206EF;
|
||||||
|
unsigned char * EXT_OPM_F0_A_C1_D1L_RR = (void *) 0xFEC206F0;
|
||||||
|
unsigned char * EXT_OPM_F1_B_C1_D1L_RR = (void *) 0xFEC206F1;
|
||||||
|
unsigned char * EXT_OPM_F2_C_C1_D1L_RR = (void *) 0xFEC206F2;
|
||||||
|
unsigned char * EXT_OPM_F3_D_C1_D1L_RR = (void *) 0xFEC206F3;
|
||||||
|
unsigned char * EXT_OPM_F4_E_C1_D1L_RR = (void *) 0xFEC206F4;
|
||||||
|
unsigned char * EXT_OPM_F5_F_C1_D1L_RR = (void *) 0xFEC206F5;
|
||||||
|
unsigned char * EXT_OPM_F6_G_C1_D1L_RR = (void *) 0xFEC206F6;
|
||||||
|
unsigned char * EXT_OPM_F7_H_C1_D1L_RR = (void *) 0xFEC206F7;
|
||||||
|
unsigned char * EXT_OPM_F8_A_C2_D1L_RR = (void *) 0xFEC206F8;
|
||||||
|
unsigned char * EXT_OPM_F9_B_C2_D1L_RR = (void *) 0xFEC206F9;
|
||||||
|
unsigned char * EXT_OPM_FA_C_C2_D1L_RR = (void *) 0xFEC206FA;
|
||||||
|
unsigned char * EXT_OPM_FB_D_C2_D1L_RR = (void *) 0xFEC206FB;
|
||||||
|
unsigned char * EXT_OPM_FC_E_C2_D1L_RR = (void *) 0xFEC206FC;
|
||||||
|
unsigned char * EXT_OPM_FD_F_C2_D1L_RR = (void *) 0xFEC206FD;
|
||||||
|
unsigned char * EXT_OPM_FE_G_C2_D1L_RR = (void *) 0xFEC206FE;
|
||||||
|
unsigned char * EXT_OPM_FF_H_C2_D1L_RR = (void *) 0xFEC206FF;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
// Internal OPM 0xFEC20C00
|
||||||
|
unsigned char * INT_OPM_01_TEST = (void *) 0xFEC20C01;
|
||||||
|
unsigned char * INT_OPM_08_KEY_ON_OFF = (void *) 0xFEC20C08;
|
||||||
|
unsigned char * INT_OPM_0F_NE_NFREQ = (void *) 0xFEC20C0F;
|
||||||
|
unsigned char * INT_OPM_10_CLK_A1 = (void *) 0xFEC20C10;
|
||||||
|
unsigned char * INT_OPM_11_CLK_A2 = (void *) 0xFEC20C11;
|
||||||
|
unsigned char * INT_OPM_12_CLK_B = (void *) 0xFEC20C12;
|
||||||
|
unsigned char * INT_OPM_14_CMS_FLAG_RST_IRQEN_LD = (void *) 0xFEC20C14;
|
||||||
|
unsigned char * INT_OPM_18_LFRQ = (void *) 0xFEC20C18;
|
||||||
|
unsigned char * INT_OPM_19_PMD_AMD = (void *) 0xFEC20C19;
|
||||||
|
unsigned char * INT_OPM_1B_CT_W = (void *) 0xFEC20C1B;
|
||||||
|
|
||||||
|
unsigned char * INT_OPM_20_A_RL_FR_CONNECT = (void *) 0xFEC20C20;
|
||||||
|
unsigned char * INT_OPM_21_B_RL_FR_CONNECT = (void *) 0xFEC20C21;
|
||||||
|
unsigned char * INT_OPM_22_C_RL_FR_CONNECT = (void *) 0xFEC20C22;
|
||||||
|
unsigned char * INT_OPM_23_D_RL_FR_CONNECT = (void *) 0xFEC20C23;
|
||||||
|
unsigned char * INT_OPM_24_E_RL_FR_CONNECT = (void *) 0xFEC20C24;
|
||||||
|
unsigned char * INT_OPM_25_F_RL_FR_CONNECT = (void *) 0xFEC20C25;
|
||||||
|
unsigned char * INT_OPM_26_G_RL_FR_CONNECT = (void *) 0xFEC20C26;
|
||||||
|
unsigned char * INT_OPM_27_H_RL_FR_CONNECT = (void *) 0xFEC20C27;
|
||||||
|
unsigned char * INT_OPM_28_A_KC = (void *) 0xFEC20C28;
|
||||||
|
unsigned char * INT_OPM_29_B_KC = (void *) 0xFEC20C29;
|
||||||
|
unsigned char * INT_OPM_2A_C_KC = (void *) 0xFEC20C2A;
|
||||||
|
unsigned char * INT_OPM_2B_D_KC = (void *) 0xFEC20C2B;
|
||||||
|
unsigned char * INT_OPM_2C_E_KC = (void *) 0xFEC20C2C;
|
||||||
|
unsigned char * INT_OPM_2D_F_KC = (void *) 0xFEC20C2D;
|
||||||
|
unsigned char * INT_OPM_2E_G_KC = (void *) 0xFEC20C2E;
|
||||||
|
unsigned char * INT_OPM_2F_H_KC = (void *) 0xFEC20C2F;
|
||||||
|
|
||||||
|
unsigned char * INT_OPM_30_A_KF = (void *) 0xFEC20C30;
|
||||||
|
unsigned char * INT_OPM_31_B_KF = (void *) 0xFEC20C31;
|
||||||
|
unsigned char * INT_OPM_32_C_KF = (void *) 0xFEC20C32;
|
||||||
|
unsigned char * INT_OPM_33_D_KF = (void *) 0xFEC20C33;
|
||||||
|
unsigned char * INT_OPM_34_E_KF = (void *) 0xFEC20C34;
|
||||||
|
unsigned char * INT_OPM_35_F_KF = (void *) 0xFEC20C35;
|
||||||
|
unsigned char * INT_OPM_36_G_KF = (void *) 0xFEC20C36;
|
||||||
|
unsigned char * INT_OPM_37_H_KF = (void *) 0xFEC20C37;
|
||||||
|
unsigned char * INT_OPM_38_A_PMS_AMS = (void *) 0xFEC20C38;
|
||||||
|
unsigned char * INT_OPM_39_B_PMS_AMS = (void *) 0xFEC20C39;
|
||||||
|
unsigned char * INT_OPM_3A_C_PMS_AMS = (void *) 0xFEC20C3A;
|
||||||
|
unsigned char * INT_OPM_3B_D_PMS_AMS = (void *) 0xFEC20C3B;
|
||||||
|
unsigned char * INT_OPM_3C_E_PMS_AMS = (void *) 0xFEC20C3C;
|
||||||
|
unsigned char * INT_OPM_3D_F_PMS_AMS = (void *) 0xFEC20C3D;
|
||||||
|
unsigned char * INT_OPM_3E_G_PMS_AMS = (void *) 0xFEC20C3E;
|
||||||
|
unsigned char * INT_OPM_3F_H_PMS_AMS = (void *) 0xFEC20C3F;
|
||||||
|
|
||||||
|
unsigned char * INT_OPM_40_A_M1_DT1_MUL = (void *) 0xFEC20C40;
|
||||||
|
unsigned char * INT_OPM_41_B_M1_DT1_MUL = (void *) 0xFEC20C41;
|
||||||
|
unsigned char * INT_OPM_42_C_M1_DT1_MUL = (void *) 0xFEC20C42;
|
||||||
|
unsigned char * INT_OPM_43_D_M1_DT1_MUL = (void *) 0xFEC20C43;
|
||||||
|
unsigned char * INT_OPM_44_E_M1_DT1_MUL = (void *) 0xFEC20C44;
|
||||||
|
unsigned char * INT_OPM_45_F_M1_DT1_MUL = (void *) 0xFEC20C45;
|
||||||
|
unsigned char * INT_OPM_46_G_M1_DT1_MUL = (void *) 0xFEC20C46;
|
||||||
|
unsigned char * INT_OPM_47_H_M1_DT1_MUL = (void *) 0xFEC20C47;
|
||||||
|
unsigned char * INT_OPM_48_A_M2_DT1_MUL = (void *) 0xFEC20C48;
|
||||||
|
unsigned char * INT_OPM_49_B_M2_DT1_MUL = (void *) 0xFEC20C49;
|
||||||
|
unsigned char * INT_OPM_4A_C_M2_DT1_MUL = (void *) 0xFEC20C4A;
|
||||||
|
unsigned char * INT_OPM_4B_D_M2_DT1_MUL = (void *) 0xFEC20C4B;
|
||||||
|
unsigned char * INT_OPM_4C_E_M2_DT1_MUL = (void *) 0xFEC20C4C;
|
||||||
|
unsigned char * INT_OPM_4D_F_M2_DT1_MUL = (void *) 0xFEC20C4D;
|
||||||
|
unsigned char * INT_OPM_4E_G_M2_DT1_MUL = (void *) 0xFEC20C4E;
|
||||||
|
unsigned char * INT_OPM_4F_H_M2_DT1_MUL = (void *) 0xFEC20C4F;
|
||||||
|
|
||||||
|
unsigned char * INT_OPM_50_A_C1_DT1_MUL = (void *) 0xFEC20C50;
|
||||||
|
unsigned char * INT_OPM_51_B_C1_DT1_MUL = (void *) 0xFEC20C51;
|
||||||
|
unsigned char * INT_OPM_52_C_C1_DT1_MUL = (void *) 0xFEC20C52;
|
||||||
|
unsigned char * INT_OPM_53_D_C1_DT1_MUL = (void *) 0xFEC20C53;
|
||||||
|
unsigned char * INT_OPM_54_E_C1_DT1_MUL = (void *) 0xFEC20C54;
|
||||||
|
unsigned char * INT_OPM_55_F_C1_DT1_MUL = (void *) 0xFEC20C55;
|
||||||
|
unsigned char * INT_OPM_56_G_C1_DT1_MUL = (void *) 0xFEC20C56;
|
||||||
|
unsigned char * INT_OPM_57_H_C1_DT1_MUL = (void *) 0xFEC20C57;
|
||||||
|
unsigned char * INT_OPM_58_A_C2_DT1_MUL = (void *) 0xFEC20C58;
|
||||||
|
unsigned char * INT_OPM_59_B_C2_DT1_MUL = (void *) 0xFEC20C59;
|
||||||
|
unsigned char * INT_OPM_5A_C_C2_DT1_MUL = (void *) 0xFEC20C5A;
|
||||||
|
unsigned char * INT_OPM_5B_D_C2_DT1_MUL = (void *) 0xFEC20C5B;
|
||||||
|
unsigned char * INT_OPM_5C_E_C2_DT1_MUL = (void *) 0xFEC20C5C;
|
||||||
|
unsigned char * INT_OPM_5D_F_C2_DT1_MUL = (void *) 0xFEC20C5D;
|
||||||
|
unsigned char * INT_OPM_5E_G_C2_DT1_MUL = (void *) 0xFEC20C5E;
|
||||||
|
unsigned char * INT_OPM_5F_H_C2_DT1_MUL = (void *) 0xFEC20C5F;
|
||||||
|
|
||||||
|
unsigned char * INT_OPM_60_A_M1_TL = (void *) 0xFEC20C60;
|
||||||
|
unsigned char * INT_OPM_61_B_M1_TL = (void *) 0xFEC20C61;
|
||||||
|
unsigned char * INT_OPM_62_C_M1_TL = (void *) 0xFEC20C62;
|
||||||
|
unsigned char * INT_OPM_63_D_M1_TL = (void *) 0xFEC20C63;
|
||||||
|
unsigned char * INT_OPM_64_E_M1_TL = (void *) 0xFEC20C64;
|
||||||
|
unsigned char * INT_OPM_65_F_M1_TL = (void *) 0xFEC20C65;
|
||||||
|
unsigned char * INT_OPM_66_G_M1_TL = (void *) 0xFEC20C66;
|
||||||
|
unsigned char * INT_OPM_67_H_M1_TL = (void *) 0xFEC20C67;
|
||||||
|
unsigned char * INT_OPM_68_A_M2_TL = (void *) 0xFEC20C68;
|
||||||
|
unsigned char * INT_OPM_69_B_M2_TL = (void *) 0xFEC20C69;
|
||||||
|
unsigned char * INT_OPM_6A_C_M2_TL = (void *) 0xFEC20C6A;
|
||||||
|
unsigned char * INT_OPM_6B_D_M2_TL = (void *) 0xFEC20C6B;
|
||||||
|
unsigned char * INT_OPM_6C_E_M2_TL = (void *) 0xFEC20C6C;
|
||||||
|
unsigned char * INT_OPM_6D_F_M2_TL = (void *) 0xFEC20C6D;
|
||||||
|
unsigned char * INT_OPM_6E_G_M2_TL = (void *) 0xFEC20C6E;
|
||||||
|
unsigned char * INT_OPM_6F_H_M2_TL = (void *) 0xFEC20C6F;
|
||||||
|
|
||||||
|
unsigned char * INT_OPM_70_A_C1_TL = (void *) 0xFEC20C70;
|
||||||
|
unsigned char * INT_OPM_71_B_C1_TL = (void *) 0xFEC20C71;
|
||||||
|
unsigned char * INT_OPM_72_C_C1_TL = (void *) 0xFEC20C72;
|
||||||
|
unsigned char * INT_OPM_73_D_C1_TL = (void *) 0xFEC20C73;
|
||||||
|
unsigned char * INT_OPM_74_E_C1_TL = (void *) 0xFEC20C74;
|
||||||
|
unsigned char * INT_OPM_75_F_C1_TL = (void *) 0xFEC20C75;
|
||||||
|
unsigned char * INT_OPM_76_G_C1_TL = (void *) 0xFEC20C76;
|
||||||
|
unsigned char * INT_OPM_77_H_C1_TL = (void *) 0xFEC20C77;
|
||||||
|
unsigned char * INT_OPM_78_A_C2_TL = (void *) 0xFEC20C78;
|
||||||
|
unsigned char * INT_OPM_79_B_C2_TL = (void *) 0xFEC20C79;
|
||||||
|
unsigned char * INT_OPM_7A_C_C2_TL = (void *) 0xFEC20C7A;
|
||||||
|
unsigned char * INT_OPM_7B_D_C2_TL = (void *) 0xFEC20C7B;
|
||||||
|
unsigned char * INT_OPM_7C_E_C2_TL = (void *) 0xFEC20C7C;
|
||||||
|
unsigned char * INT_OPM_7D_F_C2_TL = (void *) 0xFEC20C7D;
|
||||||
|
unsigned char * INT_OPM_7E_G_C2_TL = (void *) 0xFEC20C7E;
|
||||||
|
unsigned char * INT_OPM_7F_H_C2_TL = (void *) 0xFEC20C7F;
|
||||||
|
|
||||||
|
unsigned char * INT_OPM_80_A_M1_KS_AR = (void *) 0xFEC20C80;
|
||||||
|
unsigned char * INT_OPM_81_B_M1_KS_AR = (void *) 0xFEC20C81;
|
||||||
|
unsigned char * INT_OPM_82_C_M1_KS_AR = (void *) 0xFEC20C82;
|
||||||
|
unsigned char * INT_OPM_83_D_M1_KS_AR = (void *) 0xFEC20C83;
|
||||||
|
unsigned char * INT_OPM_84_E_M1_KS_AR = (void *) 0xFEC20C84;
|
||||||
|
unsigned char * INT_OPM_85_F_M1_KS_AR = (void *) 0xFEC20C85;
|
||||||
|
unsigned char * INT_OPM_86_G_M1_KS_AR = (void *) 0xFEC20C86;
|
||||||
|
unsigned char * INT_OPM_87_H_M1_KS_AR = (void *) 0xFEC20C87;
|
||||||
|
unsigned char * INT_OPM_88_A_M2_KS_AR = (void *) 0xFEC20C88;
|
||||||
|
unsigned char * INT_OPM_89_B_M2_KS_AR = (void *) 0xFEC20C89;
|
||||||
|
unsigned char * INT_OPM_8A_C_M2_KS_AR = (void *) 0xFEC20C8A;
|
||||||
|
unsigned char * INT_OPM_8B_D_M2_KS_AR = (void *) 0xFEC20C8B;
|
||||||
|
unsigned char * INT_OPM_8C_E_M2_KS_AR = (void *) 0xFEC20C8C;
|
||||||
|
unsigned char * INT_OPM_8D_F_M2_KS_AR = (void *) 0xFEC20C8D;
|
||||||
|
unsigned char * INT_OPM_8E_G_M2_KS_AR = (void *) 0xFEC20C8E;
|
||||||
|
unsigned char * INT_OPM_8F_H_M2_KS_AR = (void *) 0xFEC20C8F;
|
||||||
|
|
||||||
|
unsigned char * INT_OPM_90_A_C1_KS_AR = (void *) 0xFEC20C90;
|
||||||
|
unsigned char * INT_OPM_91_B_C1_KS_AR = (void *) 0xFEC20C91;
|
||||||
|
unsigned char * INT_OPM_92_C_C1_KS_AR = (void *) 0xFEC20C92;
|
||||||
|
unsigned char * INT_OPM_93_D_C1_KS_AR = (void *) 0xFEC20C93;
|
||||||
|
unsigned char * INT_OPM_94_E_C1_KS_AR = (void *) 0xFEC20C94;
|
||||||
|
unsigned char * INT_OPM_95_F_C1_KS_AR = (void *) 0xFEC20C95;
|
||||||
|
unsigned char * INT_OPM_96_G_C1_KS_AR = (void *) 0xFEC20C96;
|
||||||
|
unsigned char * INT_OPM_97_H_C1_KS_AR = (void *) 0xFEC20C97;
|
||||||
|
unsigned char * INT_OPM_98_A_C2_KS_AR = (void *) 0xFEC20C98;
|
||||||
|
unsigned char * INT_OPM_99_B_C2_KS_AR = (void *) 0xFEC20C99;
|
||||||
|
unsigned char * INT_OPM_9A_C_C2_KS_AR = (void *) 0xFEC20C9A;
|
||||||
|
unsigned char * INT_OPM_9B_D_C2_KS_AR = (void *) 0xFEC20C9B;
|
||||||
|
unsigned char * INT_OPM_9C_E_C2_KS_AR = (void *) 0xFEC20C9C;
|
||||||
|
unsigned char * INT_OPM_9D_F_C2_KS_AR = (void *) 0xFEC20C9D;
|
||||||
|
unsigned char * INT_OPM_9E_G_C2_KS_AR = (void *) 0xFEC20C9E;
|
||||||
|
unsigned char * INT_OPM_9F_H_C2_KS_AR = (void *) 0xFEC20C9F;
|
||||||
|
|
||||||
|
unsigned char * INT_OPM_A0_A_M1_AMS_EN_D1R = (void *) 0xFEC20CA0;
|
||||||
|
unsigned char * INT_OPM_A1_B_M1_AMS_EN_D1R = (void *) 0xFEC20CA1;
|
||||||
|
unsigned char * INT_OPM_A2_C_M1_AMS_EN_D1R = (void *) 0xFEC20CA2;
|
||||||
|
unsigned char * INT_OPM_A3_D_M1_AMS_EN_D1R = (void *) 0xFEC20CA3;
|
||||||
|
unsigned char * INT_OPM_A4_E_M1_AMS_EN_D1R = (void *) 0xFEC20CA4;
|
||||||
|
unsigned char * INT_OPM_A5_F_M1_AMS_EN_D1R = (void *) 0xFEC20CA5;
|
||||||
|
unsigned char * INT_OPM_A6_G_M1_AMS_EN_D1R = (void *) 0xFEC20CA6;
|
||||||
|
unsigned char * INT_OPM_A7_H_M1_AMS_EN_D1R = (void *) 0xFEC20CA7;
|
||||||
|
unsigned char * INT_OPM_A8_A_M2_AMS_EN_D1R = (void *) 0xFEC20CA8;
|
||||||
|
unsigned char * INT_OPM_A9_B_M2_AMS_EN_D1R = (void *) 0xFEC20CA9;
|
||||||
|
unsigned char * INT_OPM_AA_C_M2_AMS_EN_D1R = (void *) 0xFEC20CAA;
|
||||||
|
unsigned char * INT_OPM_AB_D_M2_AMS_EN_D1R = (void *) 0xFEC20CAB;
|
||||||
|
unsigned char * INT_OPM_AC_E_M2_AMS_EN_D1R = (void *) 0xFEC20CAC;
|
||||||
|
unsigned char * INT_OPM_AD_F_M2_AMS_EN_D1R = (void *) 0xFEC20CAD;
|
||||||
|
unsigned char * INT_OPM_AE_G_M2_AMS_EN_D1R = (void *) 0xFEC20CAE;
|
||||||
|
unsigned char * INT_OPM_AF_H_M2_AMS_EN_D1R = (void *) 0xFEC20CAF;
|
||||||
|
|
||||||
|
unsigned char * INT_OPM_B0_A_C1_AMS_EN_D1R = (void *) 0xFEC20CB0;
|
||||||
|
unsigned char * INT_OPM_B1_B_C1_AMS_EN_D1R = (void *) 0xFEC20CB1;
|
||||||
|
unsigned char * INT_OPM_B2_C_C1_AMS_EN_D1R = (void *) 0xFEC20CB2;
|
||||||
|
unsigned char * INT_OPM_B3_D_C1_AMS_EN_D1R = (void *) 0xFEC20CB3;
|
||||||
|
unsigned char * INT_OPM_B4_E_C1_AMS_EN_D1R = (void *) 0xFEC20CB4;
|
||||||
|
unsigned char * INT_OPM_B5_F_C1_AMS_EN_D1R = (void *) 0xFEC20CB5;
|
||||||
|
unsigned char * INT_OPM_B6_G_C1_AMS_EN_D1R = (void *) 0xFEC20CB6;
|
||||||
|
unsigned char * INT_OPM_B7_H_C1_AMS_EN_D1R = (void *) 0xFEC20CB7;
|
||||||
|
unsigned char * INT_OPM_B8_A_C2_AMS_EN_D1R = (void *) 0xFEC20CB8;
|
||||||
|
unsigned char * INT_OPM_B9_B_C2_AMS_EN_D1R = (void *) 0xFEC20CB9;
|
||||||
|
unsigned char * INT_OPM_BA_C_C2_AMS_EN_D1R = (void *) 0xFEC20CBA;
|
||||||
|
unsigned char * INT_OPM_BB_D_C2_AMS_EN_D1R = (void *) 0xFEC20CBB;
|
||||||
|
unsigned char * INT_OPM_BC_E_C2_AMS_EN_D1R = (void *) 0xFEC20CBC;
|
||||||
|
unsigned char * INT_OPM_BD_F_C2_AMS_EN_D1R = (void *) 0xFEC20CBD;
|
||||||
|
unsigned char * INT_OPM_BE_G_C2_AMS_EN_D1R = (void *) 0xFEC20CBE;
|
||||||
|
unsigned char * INT_OPM_BF_H_C2_AMS_EN_D1R = (void *) 0xFEC20CBF;
|
||||||
|
|
||||||
|
unsigned char * INT_OPM_C0_A_M1_DT2_D2R = (void *) 0xFEC20CC0;
|
||||||
|
unsigned char * INT_OPM_C1_B_M1_DT2_D2R = (void *) 0xFEC20CC1;
|
||||||
|
unsigned char * INT_OPM_C2_C_M1_DT2_D2R = (void *) 0xFEC20CC2;
|
||||||
|
unsigned char * INT_OPM_C3_D_M1_DT2_D2R = (void *) 0xFEC20CC3;
|
||||||
|
unsigned char * INT_OPM_C4_E_M1_DT2_D2R = (void *) 0xFEC20CC4;
|
||||||
|
unsigned char * INT_OPM_C5_F_M1_DT2_D2R = (void *) 0xFEC20CC5;
|
||||||
|
unsigned char * INT_OPM_C6_G_M1_DT2_D2R = (void *) 0xFEC20CC6;
|
||||||
|
unsigned char * INT_OPM_C7_H_M1_DT2_D2R = (void *) 0xFEC20CC7;
|
||||||
|
unsigned char * INT_OPM_C8_A_M2_DT2_D2R = (void *) 0xFEC20CC8;
|
||||||
|
unsigned char * INT_OPM_C9_B_M2_DT2_D2R = (void *) 0xFEC20CC9;
|
||||||
|
unsigned char * INT_OPM_CA_C_M2_DT2_D2R = (void *) 0xFEC20CCA;
|
||||||
|
unsigned char * INT_OPM_CB_D_M2_DT2_D2R = (void *) 0xFEC20CCB;
|
||||||
|
unsigned char * INT_OPM_CC_E_M2_DT2_D2R = (void *) 0xFEC20CCC;
|
||||||
|
unsigned char * INT_OPM_CD_F_M2_DT2_D2R = (void *) 0xFEC20CCD;
|
||||||
|
unsigned char * INT_OPM_CE_G_M2_DT2_D2R = (void *) 0xFEC20CCE;
|
||||||
|
unsigned char * INT_OPM_CF_H_M2_DT2_D2R = (void *) 0xFEC20CCF;
|
||||||
|
|
||||||
|
unsigned char * INT_OPM_D0_A_C1_DT2_D2R = (void *) 0xFEC20CD0;
|
||||||
|
unsigned char * INT_OPM_D1_B_C1_DT2_D2R = (void *) 0xFEC20CD1;
|
||||||
|
unsigned char * INT_OPM_D2_C_C1_DT2_D2R = (void *) 0xFEC20CD2;
|
||||||
|
unsigned char * INT_OPM_D3_D_C1_DT2_D2R = (void *) 0xFEC20CD3;
|
||||||
|
unsigned char * INT_OPM_D4_E_C1_DT2_D2R = (void *) 0xFEC20CD4;
|
||||||
|
unsigned char * INT_OPM_D5_F_C1_DT2_D2R = (void *) 0xFEC20CD5;
|
||||||
|
unsigned char * INT_OPM_D6_G_C1_DT2_D2R = (void *) 0xFEC20CD6;
|
||||||
|
unsigned char * INT_OPM_D7_H_C1_DT2_D2R = (void *) 0xFEC20CD7;
|
||||||
|
unsigned char * INT_OPM_D8_A_C2_DT2_D2R = (void *) 0xFEC20CD8;
|
||||||
|
unsigned char * INT_OPM_D9_B_C2_DT2_D2R = (void *) 0xFEC20CD9;
|
||||||
|
unsigned char * INT_OPM_DA_C_C2_DT2_D2R = (void *) 0xFEC20CDA;
|
||||||
|
unsigned char * INT_OPM_DB_D_C2_DT2_D2R = (void *) 0xFEC20CDB;
|
||||||
|
unsigned char * INT_OPM_DC_E_C2_DT2_D2R = (void *) 0xFEC20CDC;
|
||||||
|
unsigned char * INT_OPM_DD_F_C2_DT2_D2R = (void *) 0xFEC20CDD;
|
||||||
|
unsigned char * INT_OPM_DE_G_C2_DT2_D2R = (void *) 0xFEC20CDE;
|
||||||
|
unsigned char * INT_OPM_DF_H_C2_DT2_D2R = (void *) 0xFEC20CDF;
|
||||||
|
|
||||||
|
unsigned char * INT_OPM_E0_A_M1_D1L_RR = (void *) 0xFEC20CE0;
|
||||||
|
unsigned char * INT_OPM_E1_B_M1_D1L_RR = (void *) 0xFEC20CE1;
|
||||||
|
unsigned char * INT_OPM_E2_C_M1_D1L_RR = (void *) 0xFEC20CE2;
|
||||||
|
unsigned char * INT_OPM_E3_D_M1_D1L_RR = (void *) 0xFEC20CE3;
|
||||||
|
unsigned char * INT_OPM_E4_E_M1_D1L_RR = (void *) 0xFEC20CE4;
|
||||||
|
unsigned char * INT_OPM_E5_F_M1_D1L_RR = (void *) 0xFEC20CE5;
|
||||||
|
unsigned char * INT_OPM_E6_G_M1_D1L_RR = (void *) 0xFEC20CE6;
|
||||||
|
unsigned char * INT_OPM_E7_H_M1_D1L_RR = (void *) 0xFEC20CE7;
|
||||||
|
unsigned char * INT_OPM_E8_A_M2_D1L_RR = (void *) 0xFEC20CE8;
|
||||||
|
unsigned char * INT_OPM_E9_B_M2_D1L_RR = (void *) 0xFEC20CE9;
|
||||||
|
unsigned char * INT_OPM_EA_C_M2_D1L_RR = (void *) 0xFEC20CEA;
|
||||||
|
unsigned char * INT_OPM_EB_D_M2_D1L_RR = (void *) 0xFEC20CEB;
|
||||||
|
unsigned char * INT_OPM_EC_E_M2_D1L_RR = (void *) 0xFEC20CEC;
|
||||||
|
unsigned char * INT_OPM_ED_F_M2_D1L_RR = (void *) 0xFEC20CED;
|
||||||
|
unsigned char * INT_OPM_EE_G_M2_D1L_RR = (void *) 0xFEC20CEE;
|
||||||
|
unsigned char * INT_OPM_EF_H_M2_D1L_RR = (void *) 0xFEC20CEF;
|
||||||
|
|
||||||
|
unsigned char * INT_OPM_F0_A_C1_D1L_RR = (void *) 0xFEC20CF0;
|
||||||
|
unsigned char * INT_OPM_F1_B_C1_D1L_RR = (void *) 0xFEC20CF1;
|
||||||
|
unsigned char * INT_OPM_F2_C_C1_D1L_RR = (void *) 0xFEC20CF2;
|
||||||
|
unsigned char * INT_OPM_F3_D_C1_D1L_RR = (void *) 0xFEC20CF3;
|
||||||
|
unsigned char * INT_OPM_F4_E_C1_D1L_RR = (void *) 0xFEC20CF4;
|
||||||
|
unsigned char * INT_OPM_F5_F_C1_D1L_RR = (void *) 0xFEC20CF5;
|
||||||
|
unsigned char * INT_OPM_F6_G_C1_D1L_RR = (void *) 0xFEC20CF6;
|
||||||
|
unsigned char * INT_OPM_F7_H_C1_D1L_RR = (void *) 0xFEC20CF7;
|
||||||
|
unsigned char * INT_OPM_F8_A_C2_D1L_RR = (void *) 0xFEC20CF8;
|
||||||
|
unsigned char * INT_OPM_F9_B_C2_D1L_RR = (void *) 0xFEC20CF9;
|
||||||
|
unsigned char * INT_OPM_FA_C_C2_D1L_RR = (void *) 0xFEC20CFA;
|
||||||
|
unsigned char * INT_OPM_FB_D_C2_D1L_RR = (void *) 0xFEC20CFB;
|
||||||
|
unsigned char * INT_OPM_FC_E_C2_D1L_RR = (void *) 0xFEC20CFC;
|
||||||
|
unsigned char * INT_OPM_FD_F_C2_D1L_RR = (void *) 0xFEC20CFD;
|
||||||
|
unsigned char * INT_OPM_FE_G_C2_D1L_RR = (void *) 0xFEC20CFE;
|
||||||
|
unsigned char * INT_OPM_FF_H_C2_D1L_RR = (void *) 0xFEC20CFF;
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
297
src/include/A2560K/YM2612_Ext.h
Normal file
297
src/include/A2560K/YM2612_Ext.h
Normal file
|
@ -0,0 +1,297 @@
|
||||||
|
#ifndef YM2612_Ext_H_
|
||||||
|
#define YM2612_Ext_H_
|
||||||
|
|
||||||
|
|
||||||
|
// External Registers $00C20400..$00C20BFF
|
||||||
|
unsigned char * EXT_OPN2_22_LFO = (void *)0xFEC20422; // LFO enable | LFO frequency
|
||||||
|
unsigned char * EXT_OPN2_23_TIMER_A_H = (void *)0xFEC20423; // Timer A MSBs
|
||||||
|
unsigned char * EXT_OPN2_24_TIMER_A_L = (void *)0xFEC20424; // Timer A LSBs
|
||||||
|
unsigned char * EXT_OPN2_25_TIMER_B = (void *)0xFEC20425; // Timer B
|
||||||
|
unsigned char * EXT_OPN2_27_CHANEL_3_MODE = (void *)0xFEC20427; // Ch3 mode Reset B Reset A Enable B Enable A Load B Load A
|
||||||
|
unsigned char * EXT_OPN2_27_TIMER_CONF = (void *)0xFEC20427; // Ch3 mode Reset B Reset A Enable B Enable A Load B Load A
|
||||||
|
unsigned char * EXT_OPN2_28_KEY_ON_OFF = (void *)0xFEC20428; // Operator Channel
|
||||||
|
unsigned char * EXT_OPN2_29 = (void *)0xFEC20429;
|
||||||
|
unsigned char * EXT_OPN2_2A_ADC = (void *)0xFEC2042A; // DAC
|
||||||
|
unsigned char * EXT_OPN2_2B_ADC_EN = (void *)0xFEC2042B; // DAC en
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;------------------- DT1 (detune) and MUL (multiple) ----------------------------------
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;
|
||||||
|
//; MUL ranges from 0 to 15 (decimal), and multiplies the overall frequency, with the
|
||||||
|
//; exception that 0 results in multiplication by 1/2. That is, MUL=0 to 15 gives ×1/2,
|
||||||
|
//; ×1, ×2, ... ×15.
|
||||||
|
//;
|
||||||
|
//; DT1 gives small variations from the overall frequency × MUL. The MSB of DT1 is a
|
||||||
|
//; primitive sign bit, and the two LSB’s are magnitude bits. See the next page for a
|
||||||
|
//; diagram.
|
||||||
|
//;
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
unsigned char * EXT_OPN2_30_ADSR__DT1_MUL__CH1_OP1 = (void *) 0xFEC20430;
|
||||||
|
unsigned char * EXT_OPN2_31_ADSR__DT1_MUL__CH2_OP1 = (void *) 0xFEC20431;
|
||||||
|
unsigned char * EXT_OPN2_32_ADSR__DT1_MUL__CH3_OP1 = (void *) 0xFEC20432;
|
||||||
|
unsigned char * EXT_OPN2_34_ADSR__DT1_MUL__CH1_OP2 = (void *) 0xFEC20434;
|
||||||
|
unsigned char * EXT_OPN2_35_ADSR__DT1_MUL__CH2_OP2 = (void *) 0xFEC20435;
|
||||||
|
unsigned char * EXT_OPN2_36_ADSR__DT1_MUL__CH3_OP2 = (void *) 0xFEC20436;
|
||||||
|
unsigned char * EXT_OPN2_38_ADSR__DT1_MUL__CH1_OP3 = (void *) 0xFEC20438;
|
||||||
|
unsigned char * EXT_OPN2_39_ADSR__DT1_MUL__CH2_OP3 = (void *) 0xFEC20439;
|
||||||
|
unsigned char * EXT_OPN2_3A_ADSR__DT1_MUL__CH3_OP3 = (void *) 0xFEC2043A;
|
||||||
|
unsigned char * EXT_OPN2_3C_ADSR__DT1_MUL__CH1_OP4 = (void *) 0xFEC2043C;
|
||||||
|
unsigned char * EXT_OPN2_3D_ADSR__DT1_MUL__CH2_OP4 = (void *) 0xFEC2043D;
|
||||||
|
unsigned char * EXT_OPN2_3E_ADSR__DT1_MUL__CH3_OP4 = (void *) 0xFEC2043E;
|
||||||
|
unsigned char * EXT_OPN2_30_ADSR__DT1_MUL__CH1_OP5 = (void *) 0xFEC20530;
|
||||||
|
unsigned char * EXT_OPN2_31_ADSR__DT1_MUL__CH2_OP5 = (void *) 0xFEC20531;
|
||||||
|
unsigned char * EXT_OPN2_32_ADSR__DT1_MUL__CH3_OP5 = (void *) 0xFEC20532;
|
||||||
|
unsigned char * EXT_OPN2_34_ADSR__DT1_MUL__CH1_OP6 = (void *) 0xFEC20534;
|
||||||
|
unsigned char * EXT_OPN2_35_ADSR__DT1_MUL__CH2_OP6 = (void *) 0xFEC20535;
|
||||||
|
unsigned char * EXT_OPN2_36_ADSR__DT1_MUL__CH3_OP6 = (void *) 0xFEC20536;
|
||||||
|
unsigned char * EXT_OPN2_38_ADSR__DT1_MUL__CH1_OP7 = (void *) 0xFEC20538;
|
||||||
|
unsigned char * EXT_OPN2_39_ADSR__DT1_MUL__CH2_OP7 = (void *) 0xFEC20539;
|
||||||
|
unsigned char * EXT_OPN2_3A_ADSR__DT1_MUL__CH3_OP7 = (void *) 0xFEC2053A;
|
||||||
|
unsigned char * EXT_OPN2_3C_ADSR__DT1_MUL__CH1_OP8 = (void *) 0xFEC2053C;
|
||||||
|
unsigned char * EXT_OPN2_3D_ADSR__DT1_MUL__CH2_OP8 = (void *) 0xFEC2053D;
|
||||||
|
unsigned char * EXT_OPN2_3E_ADSR__DT1_MUL__CH3_OP8 = (void *) 0xFEC2053E;
|
||||||
|
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;---------------------------------- TL (total level) ----------------------------------
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;
|
||||||
|
//; TL (total level) represents the envelope’s highest amplitude, with 0 being the largest
|
||||||
|
//; and 127 (decimal) the smallest. A change of one unit is about 0.75 dB.
|
||||||
|
//;
|
||||||
|
//; To make a note softer, only change the TL of the slots (the output operators).
|
||||||
|
//; Changing the other operators will affect the flavor of the note.
|
||||||
|
//;
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
unsigned char * EXT_OPN2_40_ADSR__LT__CH1_OP1 = (void *) 0xFEC20440;
|
||||||
|
unsigned char * EXT_OPN2_41_ADSR__LT__CH2_OP1 = (void *) 0xFEC20441;
|
||||||
|
unsigned char * EXT_OPN2_42_ADSR__LT__CH3_OP1 = (void *) 0xFEC20442;
|
||||||
|
unsigned char * EXT_OPN2_44_ADSR__LT__CH1_OP2 = (void *) 0xFEC20444;
|
||||||
|
unsigned char * EXT_OPN2_45_ADSR__LT__CH2_OP2 = (void *) 0xFEC20445;
|
||||||
|
unsigned char * EXT_OPN2_46_ADSR__LT__CH3_OP2 = (void *) 0xFEC20446;
|
||||||
|
unsigned char * EXT_OPN2_48_ADSR__LT__CH1_OP3 = (void *) 0xFEC20448;
|
||||||
|
unsigned char * EXT_OPN2_49_ADSR__LT__CH2_OP3 = (void *) 0xFEC20449;
|
||||||
|
unsigned char * EXT_OPN2_4A_ADSR__LT__CH3_OP3 = (void *) 0xFEC2044A;
|
||||||
|
unsigned char * EXT_OPN2_4C_ADSR__LT__CH1_OP4 = (void *) 0xFEC2044C;
|
||||||
|
unsigned char * EXT_OPN2_4D_ADSR__LT__CH2_OP4 = (void *) 0xFEC2044D;
|
||||||
|
unsigned char * EXT_OPN2_4E_ADSR__LT__CH3_OP4 = (void *) 0xFEC2044E;
|
||||||
|
unsigned char * EXT_OPN2_40_ADSR__LT__CH1_OP5 = (void *) 0xFEC20540;
|
||||||
|
unsigned char * EXT_OPN2_41_ADSR__LT__CH2_OP5 = (void *) 0xFEC20541;
|
||||||
|
unsigned char * EXT_OPN2_42_ADSR__LT__CH3_OP5 = (void *) 0xFEC20542;
|
||||||
|
unsigned char * EXT_OPN2_44_ADSR__LT__CH1_OP6 = (void *) 0xFEC20544;
|
||||||
|
unsigned char * EXT_OPN2_45_ADSR__LT__CH2_OP6 = (void *) 0xFEC20545;
|
||||||
|
unsigned char * EXT_OPN2_46_ADSR__LT__CH3_OP6 = (void *) 0xFEC20546;
|
||||||
|
unsigned char * EXT_OPN2_48_ADSR__LT__CH1_OP7 = (void *) 0xFEC20548;
|
||||||
|
unsigned char * EXT_OPN2_49_ADSR__LT__CH2_OP7 = (void *) 0xFEC20549;
|
||||||
|
unsigned char * EXT_OPN2_4A_ADSR__LT__CH3_OP7 = (void *) 0xFEC2054A;
|
||||||
|
unsigned char * EXT_OPN2_4C_ADSR__LT__CH1_OP8 = (void *) 0xFEC2054C;
|
||||||
|
unsigned char * EXT_OPN2_4D_ADSR__LT__CH2_OP8 = (void *) 0xFEC2054D;
|
||||||
|
unsigned char * EXT_OPN2_4E_ADSR__LT__CH3_OP8 = (void *) 0xFEC2054E;
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;------------------- RS (rate scaling) and AR (attack rate) ---------------------------
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;
|
||||||
|
//; AR is the steepness of the initial amplitude rise, shown on page 5.
|
||||||
|
//;
|
||||||
|
//; RS affects AR, D1R, D2R and RR in the same way. RS is the degree to which the envelope
|
||||||
|
//; becomes narrower as the frequency becomes higher.
|
||||||
|
//;
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
unsigned char * EXT_OPN2_50_ADSR__SR_AR__CH1_OP1 = (void *) 0xFEC20450;
|
||||||
|
unsigned char * EXT_OPN2_51_ADSR__SR_AR__CH2_OP1 = (void *) 0xFEC20451;
|
||||||
|
unsigned char * EXT_OPN2_52_ADSR__SR_AR__CH3_OP1 = (void *) 0xFEC20452;
|
||||||
|
unsigned char * EXT_OPN2_54_ADSR__SR_AR__CH1_OP2 = (void *) 0xFEC20454;
|
||||||
|
unsigned char * EXT_OPN2_55_ADSR__SR_AR__CH2_OP2 = (void *) 0xFEC20455;
|
||||||
|
unsigned char * EXT_OPN2_56_ADSR__SR_AR__CH3_OP2 = (void *) 0xFEC20456;
|
||||||
|
unsigned char * EXT_OPN2_58_ADSR__SR_AR__CH1_OP3 = (void *) 0xFEC20458;
|
||||||
|
unsigned char * EXT_OPN2_59_ADSR__SR_AR__CH2_OP3 = (void *) 0xFEC20459;
|
||||||
|
unsigned char * EXT_OPN2_5A_ADSR__SR_AR__CH3_OP3 = (void *) 0xFEC2045A;
|
||||||
|
unsigned char * EXT_OPN2_5C_ADSR__SR_AR__CH1_OP4 = (void *) 0xFEC2045C;
|
||||||
|
unsigned char * EXT_OPN2_5D_ADSR__SR_AR__CH2_OP4 = (void *) 0xFEC2045D;
|
||||||
|
unsigned char * EXT_OPN2_5E_ADSR__SR_AR__CH3_OP4 = (void *) 0xFEC2045E;
|
||||||
|
unsigned char * EXT_OPN2_50_ADSR__SR_AR__CH1_OP5 = (void *) 0xFEC20550;
|
||||||
|
unsigned char * EXT_OPN2_51_ADSR__SR_AR__CH2_OP5 = (void *) 0xFEC20551;
|
||||||
|
unsigned char * EXT_OPN2_52_ADSR__SR_AR__CH3_OP5 = (void *) 0xFEC20552;
|
||||||
|
unsigned char * EXT_OPN2_54_ADSR__SR_AR__CH1_OP6 = (void *) 0xFEC20554;
|
||||||
|
unsigned char * EXT_OPN2_55_ADSR__SR_AR__CH2_OP6 = (void *) 0xFEC20555;
|
||||||
|
unsigned char * EXT_OPN2_56_ADSR__SR_AR__CH3_OP6 = (void *) 0xFEC20556;
|
||||||
|
unsigned char * EXT_OPN2_58_ADSR__SR_AR__CH1_OP7 = (void *) 0xFEC20558;
|
||||||
|
unsigned char * EXT_OPN2_59_ADSR__SR_AR__CH2_OP7 = (void *) 0xFEC20559;
|
||||||
|
unsigned char * EXT_OPN2_5A_ADSR__SR_AR__CH3_OP7 = (void *) 0xFEC2055A;
|
||||||
|
unsigned char * EXT_OPN2_5C_ADSR__SR_AR__CH1_OP8 = (void *) 0xFEC2055C;
|
||||||
|
unsigned char * EXT_OPN2_5D_ADSR__SR_AR__CH2_OP8 = (void *) 0xFEC2055D;
|
||||||
|
unsigned char * EXT_OPN2_5E_ADSR__SR_AR__CH3_OP8 = (void *) 0xFEC2055E;
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;-------------- AM modulation enable amd D1R (first decay rate) -----------------------
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;
|
||||||
|
//; D1R (first decay rate) is the initial steep amplitude decay rate (see page 4). It is,
|
||||||
|
//; like all rates, 0-31 in value and affected by RS.
|
||||||
|
//;
|
||||||
|
//; AM is the amplitude modulation enable, whether of not this operator will be subject to
|
||||||
|
//; amplitude modulation by the LFO. This bit is not relevant unless both the LFO is
|
||||||
|
//; enabled and register B4′s AMS (amplitude modulation sensitivity) is non-zero.
|
||||||
|
//;
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
unsigned char * EXT_OPN2_60_ADSR__AM_D1R__CH1_OP1 = (void *) 0xFEC20460;
|
||||||
|
unsigned char * EXT_OPN2_61_ADSR__AM_D1R__CH2_OP1 = (void *) 0xFEC20461;
|
||||||
|
unsigned char * EXT_OPN2_62_ADSR__AM_D1R__CH3_OP1 = (void *) 0xFEC20462;
|
||||||
|
unsigned char * EXT_OPN2_64_ADSR__AM_D1R__CH1_OP2 = (void *) 0xFEC20464;
|
||||||
|
unsigned char * EXT_OPN2_65_ADSR__AM_D1R__CH2_OP2 = (void *) 0xFEC20465;
|
||||||
|
unsigned char * EXT_OPN2_66_ADSR__AM_D1R__CH3_OP2 = (void *) 0xFEC20466;
|
||||||
|
unsigned char * EXT_OPN2_68_ADSR__AM_D1R__CH1_OP3 = (void *) 0xFEC20468;
|
||||||
|
unsigned char * EXT_OPN2_69_ADSR__AM_D1R__CH2_OP3 = (void *) 0xFEC20469;
|
||||||
|
unsigned char * EXT_OPN2_6A_ADSR__AM_D1R__CH3_OP3 = (void *) 0xFEC2046A;
|
||||||
|
unsigned char * EXT_OPN2_6C_ADSR__AM_D1R__CH1_OP4 = (void *) 0xFEC2046C;
|
||||||
|
unsigned char * EXT_OPN2_6D_ADSR__AM_D1R__CH2_OP4 = (void *) 0xFEC2046D;
|
||||||
|
unsigned char * EXT_OPN2_6E_ADSR__AM_D1R__CH3_OP4 = (void *) 0xFEC2046E;
|
||||||
|
unsigned char * EXT_OPN2_60_ADSR__AM_D1R__CH1_OP5 = (void *) 0xFEC20560;
|
||||||
|
unsigned char * EXT_OPN2_61_ADSR__AM_D1R__CH2_OP5 = (void *) 0xFEC20561;
|
||||||
|
unsigned char * EXT_OPN2_62_ADSR__AM_D1R__CH3_OP5 = (void *) 0xFEC20562;
|
||||||
|
unsigned char * EXT_OPN2_64_ADSR__AM_D1R__CH1_OP6 = (void *) 0xFEC20564;
|
||||||
|
unsigned char * EXT_OPN2_65_ADSR__AM_D1R__CH2_OP6 = (void *) 0xFEC20565;
|
||||||
|
unsigned char * EXT_OPN2_66_ADSR__AM_D1R__CH3_OP6 = (void *) 0xFEC20566;
|
||||||
|
unsigned char * EXT_OPN2_68_ADSR__AM_D1R__CH1_OP7 = (void *) 0xFEC20568;
|
||||||
|
unsigned char * EXT_OPN2_69_ADSR__AM_D1R__CH2_OP7 = (void *) 0xFEC20569;
|
||||||
|
unsigned char * EXT_OPN2_6A_ADSR__AM_D1R__CH3_OP7 = (void *) 0xFEC2056A;
|
||||||
|
unsigned char * EXT_OPN2_6C_ADSR__AM_D1R__CH1_OP8 = (void *) 0xFEC2056C;
|
||||||
|
unsigned char * EXT_OPN2_6D_ADSR__AM_D1R__CH2_OP8 = (void *) 0xFEC2056D;
|
||||||
|
unsigned char * EXT_OPN2_6E_ADSR__AM_D1R__CH3_OP8 = (void *) 0xFEC2056E;
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;-------------------------- D2R (secondary decay rate) --------------------------------
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;
|
||||||
|
//; D2R (secondary decay rate) is the long tail off of the sound that continues as long
|
||||||
|
//; as the key is depressed.
|
||||||
|
//;
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
unsigned char * EXT_OPN2_70_ADSR__D2R__CH1_OP1 = (void *) 0xFEC20470;
|
||||||
|
unsigned char * EXT_OPN2_71_ADSR__D2R__CH2_OP1 = (void *) 0xFEC20471;
|
||||||
|
unsigned char * EXT_OPN2_72_ADSR__D2R__CH3_OP1 = (void *) 0xFEC20472;
|
||||||
|
unsigned char * EXT_OPN2_74_ADSR__D2R__CH1_OP2 = (void *) 0xFEC20474;
|
||||||
|
unsigned char * EXT_OPN2_75_ADSR__D2R__CH2_OP2 = (void *) 0xFEC20475;
|
||||||
|
unsigned char * EXT_OPN2_76_ADSR__D2R__CH3_OP2 = (void *) 0xFEC20476;
|
||||||
|
unsigned char * EXT_OPN2_78_ADSR__D2R__CH1_OP3 = (void *) 0xFEC20478;
|
||||||
|
unsigned char * EXT_OPN2_79_ADSR__D2R__CH2_OP3 = (void *) 0xFEC20479;
|
||||||
|
unsigned char * EXT_OPN2_7A_ADSR__D2R__CH3_OP3 = (void *) 0xFEC2047A;
|
||||||
|
unsigned char * EXT_OPN2_7C_ADSR__D2R__CH1_OP4 = (void *) 0xFEC2047C;
|
||||||
|
unsigned char * EXT_OPN2_7D_ADSR__D2R__CH2_OP4 = (void *) 0xFEC2047D;
|
||||||
|
unsigned char * EXT_OPN2_7E_ADSR__D2R__CH3_OP4 = (void *) 0xFEC2047E;
|
||||||
|
unsigned char * EXT_OPN2_70_ADSR__D2R__CH1_OP5 = (void *) 0xFEC20570;
|
||||||
|
unsigned char * EXT_OPN2_71_ADSR__D2R__CH2_OP5 = (void *) 0xFEC20571;
|
||||||
|
unsigned char * EXT_OPN2_72_ADSR__D2R__CH3_OP5 = (void *) 0xFEC20572;
|
||||||
|
unsigned char * EXT_OPN2_74_ADSR__D2R__CH1_OP6 = (void *) 0xFEC20574;
|
||||||
|
unsigned char * EXT_OPN2_75_ADSR__D2R__CH2_OP6 = (void *) 0xFEC20575;
|
||||||
|
unsigned char * EXT_OPN2_76_ADSR__D2R__CH3_OP6 = (void *) 0xFEC20576;
|
||||||
|
unsigned char * EXT_OPN2_78_ADSR__D2R__CH1_OP7 = (void *) 0xFEC20578;
|
||||||
|
unsigned char * EXT_OPN2_79_ADSR__D2R__CH2_OP7 = (void *) 0xFEC20579;
|
||||||
|
unsigned char * EXT_OPN2_7A_ADSR__D2R__CH3_OP7 = (void *) 0xFEC2057A;
|
||||||
|
unsigned char * EXT_OPN2_7C_ADSR__D2R__CH1_OP8 = (void *) 0xFEC2057C;
|
||||||
|
unsigned char * EXT_OPN2_7D_ADSR__D2R__CH2_OP8 = (void *) 0xFEC2057D;
|
||||||
|
unsigned char * EXT_OPN2_7E_ADSR__D2R__CH3_OP8 = (void *) 0xFEC2057E;
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;-------------------------- D2R (secondary decay rate) --------------------------------
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;
|
||||||
|
//; D2R (secondary decay rate) is the long tail off of the sound that continues as long
|
||||||
|
//; as the key is depressed.
|
||||||
|
//;
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
unsigned char * EXT_OPN2_80_ADSR__D1L_RR__CH1_OP1 = (void *) 0xFEC20480;
|
||||||
|
unsigned char * EXT_OPN2_81_ADSR__D1L_RR__CH2_OP1 = (void *) 0xFEC20481;
|
||||||
|
unsigned char * EXT_OPN2_82_ADSR__D1L_RR__CH3_OP1 = (void *) 0xFEC20482;
|
||||||
|
unsigned char * EXT_OPN2_84_ADSR__D1L_RR__CH1_OP2 = (void *) 0xFEC20484;
|
||||||
|
unsigned char * EXT_OPN2_85_ADSR__D1L_RR__CH2_OP2 = (void *) 0xFEC20485;
|
||||||
|
unsigned char * EXT_OPN2_86_ADSR__D1L_RR__CH3_OP2 = (void *) 0xFEC20486;
|
||||||
|
unsigned char * EXT_OPN2_88_ADSR__D1L_RR__CH1_OP3 = (void *) 0xFEC20488;
|
||||||
|
unsigned char * EXT_OPN2_89_ADSR__D1L_RR__CH2_OP3 = (void *) 0xFEC20489;
|
||||||
|
unsigned char * EXT_OPN2_8A_ADSR__D1L_RR__CH3_OP3 = (void *) 0xFEC2048A;
|
||||||
|
unsigned char * EXT_OPN2_8C_ADSR__D1L_RR__CH1_OP4 = (void *) 0xFEC2048C;
|
||||||
|
unsigned char * EXT_OPN2_8D_ADSR__D1L_RR__CH2_OP4 = (void *) 0xFEC2048D;
|
||||||
|
unsigned char * EXT_OPN2_8E_ADSR__D1L_RR__CH3_OP4 = (void *) 0xFEC2048E;
|
||||||
|
unsigned char * EXT_OPN2_80_ADSR__D1L_RR__CH1_OP5 = (void *) 0xFEC20580;
|
||||||
|
unsigned char * EXT_OPN2_81_ADSR__D1L_RR__CH2_OP5 = (void *) 0xFEC20581;
|
||||||
|
unsigned char * EXT_OPN2_82_ADSR__D1L_RR__CH3_OP5 = (void *) 0xFEC20582;
|
||||||
|
unsigned char * EXT_OPN2_84_ADSR__D1L_RR__CH1_OP6 = (void *) 0xFEC20584;
|
||||||
|
unsigned char * EXT_OPN2_85_ADSR__D1L_RR__CH2_OP6 = (void *) 0xFEC20585;
|
||||||
|
unsigned char * EXT_OPN2_86_ADSR__D1L_RR__CH3_OP6 = (void *) 0xFEC20586;
|
||||||
|
unsigned char * EXT_OPN2_88_ADSR__D1L_RR__CH1_OP7 = (void *) 0xFEC20588;
|
||||||
|
unsigned char * EXT_OPN2_89_ADSR__D1L_RR__CH2_OP7 = (void *) 0xFEC20589;
|
||||||
|
unsigned char * EXT_OPN2_8A_ADSR__D1L_RR__CH3_OP7 = (void *) 0xFEC2058A;
|
||||||
|
unsigned char * EXT_OPN2_8C_ADSR__D1L_RR__CH1_OP8 = (void *) 0xFEC2058C;
|
||||||
|
unsigned char * EXT_OPN2_8D_ADSR__D1L_RR__CH2_OP8 = (void *) 0xFEC2058D;
|
||||||
|
unsigned char * EXT_OPN2_8E_ADSR__D1L_RR__CH3_OP8 = (void *) 0xFEC2058E;
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;------------------------------------ SSG-EG ------------------------------------------
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
//;
|
||||||
|
//; This register is proprietary and should be set to zero.
|
||||||
|
//;
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
unsigned char * EXT_OPN2_90_ADSR__D1L_RR__CH1_OP1 = (void *) 0xFEC20490;
|
||||||
|
unsigned char * EXT_OPN2_91_ADSR__D1L_RR__CH2_OP1 = (void *) 0xFEC20491;
|
||||||
|
unsigned char * EXT_OPN2_92_ADSR__D1L_RR__CH3_OP1 = (void *) 0xFEC20492;
|
||||||
|
unsigned char * EXT_OPN2_94_ADSR__D1L_RR__CH1_OP2 = (void *) 0xFEC20494;
|
||||||
|
unsigned char * EXT_OPN2_95_ADSR__D1L_RR__CH2_OP2 = (void *) 0xFEC20495;
|
||||||
|
unsigned char * EXT_OPN2_96_ADSR__D1L_RR__CH3_OP2 = (void *) 0xFEC20496;
|
||||||
|
unsigned char * EXT_OPN2_98_ADSR__D1L_RR__CH1_OP3 = (void *) 0xFEC20498;
|
||||||
|
unsigned char * EXT_OPN2_99_ADSR__D1L_RR__CH2_OP3 = (void *) 0xFEC20499;
|
||||||
|
unsigned char * EXT_OPN2_9A_ADSR__D1L_RR__CH3_OP3 = (void *) 0xFEC2049A;
|
||||||
|
unsigned char * EXT_OPN2_9C_ADSR__D1L_RR__CH1_OP4 = (void *) 0xFEC2049C;
|
||||||
|
unsigned char * EXT_OPN2_9D_ADSR__D1L_RR__CH2_OP4 = (void *) 0xFEC2049D;
|
||||||
|
unsigned char * EXT_OPN2_9E_ADSR__D1L_RR__CH3_OP4 = (void *) 0xFEC2049E;
|
||||||
|
unsigned char * EXT_OPN2_90_ADSR__D1L_RR__CH4_OP1 = (void *) 0xFEC20590;
|
||||||
|
unsigned char * EXT_OPN2_91_ADSR__D1L_RR__CH5_OP1 = (void *) 0xFEC20591;
|
||||||
|
unsigned char * EXT_OPN2_92_ADSR__D1L_RR__CH6_OP1 = (void *) 0xFEC20592;
|
||||||
|
unsigned char * EXT_OPN2_94_ADSR__D1L_RR__CH4_OP2 = (void *) 0xFEC20594;
|
||||||
|
unsigned char * EXT_OPN2_95_ADSR__D1L_RR__CH5_OP2 = (void *) 0xFEC20595;
|
||||||
|
unsigned char * EXT_OPN2_96_ADSR__D1L_RR__CH6_OP2 = (void *) 0xFEC20596;
|
||||||
|
unsigned char * EXT_OPN2_98_ADSR__D1L_RR__CH4_OP3 = (void *) 0xFEC20598;
|
||||||
|
unsigned char * EXT_OPN2_99_ADSR__D1L_RR__CH5_OP3 = (void *) 0xFEC20599;
|
||||||
|
unsigned char * EXT_OPN2_9A_ADSR__D1L_RR__CH6_OP3 = (void *) 0xFEC2059A;
|
||||||
|
unsigned char * EXT_OPN2_9C_ADSR__D1L_RR__CH4_OP4 = (void *) 0xFEC2059C;
|
||||||
|
unsigned char * EXT_OPN2_9D_ADSR__D1L_RR__CH5_OP4 = (void *) 0xFEC2059D;
|
||||||
|
unsigned char * EXT_OPN2_9E_ADSR__D1L_RR__CH6_OP4 = (void *) 0xFEC2059E;
|
||||||
|
//;--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
unsigned char * EXT_OPN2_A0_CH1_FREQ_L = (void *) 0xFEC204A0; //Frequency number LSB
|
||||||
|
unsigned char * EXT_OPN2_A1_CH2_FREQ_L = (void *) 0xFEC204A1; //Frequency number LSB
|
||||||
|
unsigned char * EXT_OPN2_A2_CH3_FREQ_L = (void *) 0xFEC204A2; //Frequency number LSB
|
||||||
|
unsigned char * EXT_OPN2_A2_CH3_FREQ_OP1_L = (void *) 0xFEC204A2; //Frequency number LSB Chanel 3 Operator 1 if special mode
|
||||||
|
unsigned char * EXT_OPN2_A8_CH3_FREQ_OP2_L = (void *) 0xFEC204A8; //Frequency number LSB Chanel 3 Operator 2 if special mode
|
||||||
|
unsigned char * EXT_OPN2_A9_CH3_FREQ_OP3_L = (void *) 0xFEC204A9; //Frequency number LSB Chanel 3 Operator 3 if special mode
|
||||||
|
unsigned char * EXT_OPN2_AA_CH3_FREQ_OP4_L = (void *) 0xFEC204AA; //Frequency number LSB Chanel 3 Operator 4 if special mode
|
||||||
|
unsigned char * EXT_OPN2_A0_CH4_FREQ_L = (void *) 0xFEC205A0; //Frequency number LSB
|
||||||
|
unsigned char * EXT_OPN2_A1_CH5_FREQ_L = (void *) 0xFEC205A1; //Frequency number LSB
|
||||||
|
unsigned char * EXT_OPN2_A2_CH6_FREQ_L = (void *) 0xFEC205A2; //Frequency number LSB
|
||||||
|
|
||||||
|
unsigned char * EXT_OPN2_A4_CH1_OCTAVE_FREQ_H = (void *) 0xFEC204A4; //OCTAVE and Frequency number MSB
|
||||||
|
unsigned char * EXT_OPN2_A5_CH2_OCTAVE_FREQ_H = (void *) 0xFEC204A5; //OCTAVE and Frequency number MSB
|
||||||
|
unsigned char * EXT_OPN2_A6_CH3_OCTAVE_FREQ_H = (void *) 0xFEC204A6; //OCTAVE and Frequency number MSB
|
||||||
|
unsigned char * EXT_OPN2_A6_CH3_OCTAVE_FREQ_OP1_H = (void *) 0xFEC204A6; //OCTAVE and Frequency number MSB Chanel 3 Operator 1 if special mode
|
||||||
|
unsigned char * EXT_OPN2_AC_CH3_OCTAVE_FREQ_OP2_H = (void *) 0xFEC204AC; //OCTAVE and Frequency number MSB Chanel 3 Operator 2 if special mode
|
||||||
|
unsigned char * EXT_OPN2_AD_CH3_OCTAVE_FREQ_OP3_H = (void *) 0xFEC204AD; //OCTAVE and Frequency number MSB Chanel 3 Operator 3 if special mode
|
||||||
|
unsigned char * EXT_OPN2_AE_CH3_OCTAVE_FREQ_OP4_H = (void *) 0xFEC204AE; //OCTAVE and Frequency number MSB Chanel 3 Operator 4 if special mode
|
||||||
|
unsigned char * EXT_OPN2_A4_CH4_OCTAVE_FREQ_H = (void *) 0xFEC205A4; //OCTAVE and Frequency number MSB
|
||||||
|
unsigned char * EXT_OPN2_A5_CH5_OCTAVE_FREQ_H = (void *) 0xFEC205A5; //OCTAVE and Frequency number MSB
|
||||||
|
unsigned char * EXT_OPN2_A6_CH6_OCTAVE_FREQ_H = (void *) 0xFEC205A6; //OCTAVE and Frequency number MSB
|
||||||
|
|
||||||
|
//; Feedback is the degree to which operator 1 feeds back into itself.
|
||||||
|
//; The algorithm is the type of inter-operator connection used
|
||||||
|
unsigned char * EXT_OPN2_B0_CH1_FEEDBACK_ALGO = (void *)0xFEC204B0;
|
||||||
|
unsigned char * EXT_OPN2_B1_CH2_FEEDBACK_ALGO = (void *)0xFEC204B1;
|
||||||
|
unsigned char * EXT_OPN2_B2_CH3_FEEDBACK_ALGO = (void *)0xFEC204B2;
|
||||||
|
unsigned char * EXT_OPN2_B0_CH4_FEEDBACK_ALGO = (void *)0xFEC205B0;
|
||||||
|
unsigned char * EXT_OPN2_B1_CH5_FEEDBACK_ALGO = (void *)0xFEC205B1;
|
||||||
|
unsigned char * EXT_OPN2_B2_CH6_FEEDBACK_ALGO = (void *)0xFEC205B2;
|
||||||
|
|
||||||
|
//; Register B4H contains stereo output control and LFO sensitivity control.
|
||||||
|
unsigned char * EXT_OPN2_B4_CH1_L_R_AMS_FMS = (void *)0xFEC204B0;
|
||||||
|
unsigned char * EXT_OPN2_B5_CH2_L_R_AMS_FMS = (void *)0xFEC204B1;
|
||||||
|
unsigned char * EXT_OPN2_B6_CH3_L_R_AMS_FMS = (void *)0xFEC204B2;
|
||||||
|
unsigned char * EXT_OPN2_B4_CH4_L_R_AMS_FMS = (void *)0xFEC205B0;
|
||||||
|
unsigned char * EXT_OPN2_B5_CH5_L_R_AMS_FMS = (void *)0xFEC205B1;
|
||||||
|
unsigned char * EXT_OPN2_B6_CH6_L_R_AMS_FMS = (void *)0xFEC205B2;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
43
src/include/A2560K/fdc_a2560k.h
Normal file
43
src/include/A2560K/fdc_a2560k.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Define the locations of all the FDC registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FDC_A2560K_H
|
||||||
|
#define __FDC_A2560K_H
|
||||||
|
|
||||||
|
#define FDC_BASE ((volatile unsigned char *)0xFEC023F0)
|
||||||
|
#define FDC_DOR ((volatile unsigned char *)0xFEC023F2) /* Read/Write - Digital Output Register */
|
||||||
|
// FDC_DOR_DSEL0 = $01 ; Drive 0 Select
|
||||||
|
// FDC_DOR_DSEL1 = $02 ; Drive 1 Select
|
||||||
|
// FDC_DOR_NRESET = $04 ; Reset the FDC
|
||||||
|
// FDC_DOR_DMAEN = $08 ; Enable DMA
|
||||||
|
// FDC_DOR_MOT0 = $10 ; Turn on motor 0
|
||||||
|
// FDC_DOR_MOT1 = $20 ; Turn on motor 1
|
||||||
|
// FDC_DOR_MOT2 = $40 ; Turn on motor 2
|
||||||
|
// FDC_DOR_MOT3 = $80 ; Turn on motor 3
|
||||||
|
|
||||||
|
#define FDC_MSR ((volatile unsigned char *)0xFEC023F4) /* Read - Main Status Register */
|
||||||
|
// FDC_MSR_DRV0BSY = $01 ; Indicates if drive 0 is busy
|
||||||
|
// FDC_MSR_DRV1BSY = $02 ; Indicates if drive 1 is busy
|
||||||
|
// FDC_MSR_CMDBSY = $10 ; Indicates if a command is in progress
|
||||||
|
// FDC_MSR_NONDMA = $20 ;
|
||||||
|
// FDC_MSR_DIO = $40 ; Data direction: 1 = read, 0 = write
|
||||||
|
// FDC_MSR_RQM = $80 ; 1 = host can transfer data, 0 = host must wait
|
||||||
|
|
||||||
|
#define FDC_DSR ((volatile unsigned char *)0xFEC023F4) /* Write - Data Select Register */
|
||||||
|
// ; Bit[0..1] = data rate
|
||||||
|
// ; Bit[2..4] = precompensation select
|
||||||
|
// FDC_DSR_LOPWR = $40 ; Turn on low power mode
|
||||||
|
// FDC_DSR_RESET = $80 ; Software reset of the FDC
|
||||||
|
|
||||||
|
#define FDC_DATA ((volatile unsigned char *)0xFEC023F5) /* Read/Write - Data - FIFO */
|
||||||
|
|
||||||
|
#define FDC_RSV ((volatile unsigned char *)0xFEC023F6) /* Reserved */
|
||||||
|
|
||||||
|
#define FDC_DIR ((volatile unsigned char *)0xFEC023F7) /* Read - Digital Input Register */
|
||||||
|
// FDC_DIR_DSKCHG = $80 ; Indicates if the disk has changed
|
||||||
|
|
||||||
|
#define FDC_CCR ((volatile unsigned char *)0xFEC023F7) /* Write - Configuration Control Register */
|
||||||
|
// ; Bit[0..1] = Data rate
|
||||||
|
|
||||||
|
#endif
|
58
src/include/A2560K/gabe_a2560k.h
Normal file
58
src/include/A2560K/gabe_a2560k.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/**
|
||||||
|
* @file gabe_a2560k.h
|
||||||
|
*
|
||||||
|
* Define miscellaneous GABE registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GABE_A2560K_H
|
||||||
|
#define __GABE_A2560K_H
|
||||||
|
|
||||||
|
#define GABE_CTRL_REG ((volatile unsigned int *)0xFEC00000)
|
||||||
|
#define POWER_ON_LED 0x00000001
|
||||||
|
#define SDCARD_LED 0x00000002
|
||||||
|
#define BUZZER_CONTROL 0x00000010
|
||||||
|
#define MANUAL_RESET 0x00008000 // Make sure the word "DEAD" is written in GABE_RESET_ID
|
||||||
|
|
||||||
|
#define GABE_LFSR_REG0 ((volatile unsigned int *)0xFEC00004)
|
||||||
|
|
||||||
|
#define RGB_LED ((volatile unsigned int *)0xFEC00008) // Writing Only - A2560K Only - 0x__RRGGBB
|
||||||
|
#define GABE_LFSR_STATDATA ((volatile unsigned int *)0xFEC00008) // Read Only
|
||||||
|
|
||||||
|
#define GABE_SUBVER_ID ((volatile unsigned int *)0xFEC0000C) // Subversion[31:16], Machine ID[3:2] - Read Only
|
||||||
|
#define GABE_CPU_ID_MASK 0x0000FF00
|
||||||
|
#define GABE_CPU_SPD_MASK 0x000000E0
|
||||||
|
#define GABE_ID_MASK 0x0000000C
|
||||||
|
#define GABE_CHIP_SV_MASK 0xFFFF0000
|
||||||
|
|
||||||
|
#define GABE_CHIP_VERSION ((volatile unsigned int *)0xFEC00010) // Number[31:16], Version[15:0]
|
||||||
|
#define GABE_CHIP_V_MASK 0x0000FFFF
|
||||||
|
#define GABE_CHIP_N_MASK 0xFFFF0000
|
||||||
|
|
||||||
|
#define GABE_FIRMWARE_DATE ((volatile unsigned int *)0xFEC00014) // xxDDMMYY
|
||||||
|
#define GABE_FIRMWARE_DATE_YEAR_MASK 0x000000FF
|
||||||
|
#define GABE_FIRMWARE_DATE_MONTH_MASK 0x0000FF00
|
||||||
|
#define GABE_FIRMWARE_DATE_DAY_MASK 0x00FF0000
|
||||||
|
|
||||||
|
#define GABE_DIP_REG ((volatile unsigned int *)0xFEC00518)
|
||||||
|
#define GABE_DIP_BOOT_MASK 0x00000003 /* Mask for the boot mode: */
|
||||||
|
#define GABE_DIP_USER_MASK 0x00000700 /* Mask for the user switches: */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 16-bit register controlling the key of the A2560K built-in keyboard
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define GABE_MO_LEDS ((volatile unsigned long *)0xFEC0000C)
|
||||||
|
#define GABE_MO_LED_0_B 0x00000001 /* LED 0 (Close to DEL key) -- Blue ON */
|
||||||
|
#define GABE_MO_LED_0_G 0x00000002 /* LED 0 (Close to DEL key) -- Green ON */
|
||||||
|
#define GABE_MO_LED_0_R 0x00000004 /* LED 0 (Close to DEL key) -- Red ON */
|
||||||
|
#define GABE_MO_LED_1_B 0x00000008 /* LED 1 (Below #0) -- Blue ON */
|
||||||
|
#define GABE_MO_LED_1_G 0x00000010 /* LED 1 (Below #0) -- Green ON */
|
||||||
|
#define GABE_MO_LED_1_R 0x00000020 /* LED 1 (Below #0) -- Red ON */
|
||||||
|
#define GABE_MO_LED_2_B 0x00000040 /* LED 2 (above arrow) -- Blue ON */
|
||||||
|
#define GABE_MO_LED_2_G 0x00000080 /* LED 2 (above arrow) -- Green ON */
|
||||||
|
#define GABE_MO_LED_2_R 0x00000100 /* LED 2 (above arrow) -- Red ON */
|
||||||
|
#define GABE_MO_LED_3_B 0x00000200 /* LED 2 (caps lock, Rev C) -- Blue ON */
|
||||||
|
#define GABE_MO_LED_3_G 0x00000400 /* LED 2 (caps lock, Rev C) -- Green ON */
|
||||||
|
#define GABE_MO_LED_3_R 0x00000800 /* LED 2 (caps lock, Rev C) -- Red ON */
|
||||||
|
|
||||||
|
#endif
|
18
src/include/A2560K/pata_a2560k.h
Normal file
18
src/include/A2560K/pata_a2560k.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Definitions to access the PATA port on the A2560K
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PATA_A2560K_H
|
||||||
|
#define __PATA_A2560K_H
|
||||||
|
|
||||||
|
#define PATA_DATA_16 ((volatile unsigned short *)0xFEC00400)
|
||||||
|
#define PATA_DATA_8 ((volatile unsigned char *)0xFEC00400)
|
||||||
|
#define PATA_ERROR ((volatile unsigned char *)0xFEC00402)
|
||||||
|
#define PATA_SECT_CNT ((volatile unsigned char *)0xFEC00404)
|
||||||
|
#define PATA_SECT_SRT ((volatile unsigned char *)0xFEC00406)
|
||||||
|
#define PATA_CLDR_LO ((volatile unsigned char *)0xFEC00408)
|
||||||
|
#define PATA_CLDR_HI ((volatile unsigned char *)0xFEC0040A)
|
||||||
|
#define PATA_HEAD ((volatile unsigned char *)0xFEC0040C)
|
||||||
|
#define PATA_CMD_STAT ((volatile unsigned char *)0xFEC0040E)
|
||||||
|
|
||||||
|
#endif
|
14
src/include/A2560K/ps2_a2560k.h
Normal file
14
src/include/A2560K/ps2_a2560k.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef __PS2_A2560K_H
|
||||||
|
#define __PS2_A2560K_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ports for the PS/2 keyboard and mouse on the A2560K
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PS2_STATUS ((unsigned char *)0xFEC02064)
|
||||||
|
#define PS2_CMD_BUF ((unsigned char *)0xFEC02064)
|
||||||
|
#define PS2_OUT_BUF ((unsigned char *)0xFEC02060)
|
||||||
|
#define PS2_INPT_BUF ((unsigned char *)0xFEC02060)
|
||||||
|
#define PS2_DATA_BUF ((unsigned char *)0xFEC02060)
|
||||||
|
|
||||||
|
#endif
|
39
src/include/A2560K/sdc_a2560k.h
Normal file
39
src/include/A2560K/sdc_a2560k.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Definitions for access to the SDC controller
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SDC_A2560K_H
|
||||||
|
#define __SDC_A2560K_H
|
||||||
|
|
||||||
|
#define GABE_SDC_REG ((volatile unsigned int *)0xFEC00518)
|
||||||
|
#define GABE_SDC_PRESENT 0x01000000 /* Is an SD card present? --- 0:Yes, 1:No */
|
||||||
|
#define GABE_SDC_WPROT 0x02000000 /* Is the SD card write protected? --- 0:Yes, 1:No */
|
||||||
|
#define GABE_BOOTMODE_0 0x00000001 /* DIP switch: boot mode 0 */
|
||||||
|
#define GABE_BOOTMODE_1 0x00000002 /* DIP switch: boot mode 1 */
|
||||||
|
#define GABE_DIP_USER_0 0x00000100 /* DIP switch: User 0 */
|
||||||
|
#define GABE_DIP_USER_1 0x00000200 /* DIP switch: User 1 */
|
||||||
|
|
||||||
|
#define SDC_VERSION_REG ((unsigned char *)0xFEC00300)
|
||||||
|
#define SDC_CONTROL_REG ((unsigned char *)0xFEC00301)
|
||||||
|
#define SDC_TRANS_TYPE_REG ((unsigned char *)0xFEC00302)
|
||||||
|
|
||||||
|
#define SDC_TRANS_CONTROL_REG ((unsigned char *)0xFEC00303)
|
||||||
|
#define SDC_TRANS_STATUS_REG ((unsigned char *)0xFEC00304)
|
||||||
|
#define SDC_TRANS_ERROR_REG ((unsigned char *)0xFEC00305)
|
||||||
|
#define SDC_DIRECT_ACCESS_REG ((unsigned char *)0xFEC00306)
|
||||||
|
#define SDC_SD_ADDR_7_0_REG ((unsigned char *)0xFEC00307)
|
||||||
|
#define SDC_SD_ADDR_15_8_REG ((unsigned char *)0xFEC00308)
|
||||||
|
#define SDC_SD_ADDR_23_16_REG ((unsigned char *)0xFEC00309)
|
||||||
|
#define SDC_SD_ADDR_31_24_REG ((unsigned char *)0xFEC0030A)
|
||||||
|
|
||||||
|
#define SDC_SPI_CLK_DEL_REG ((unsigned char *)0xFEC0030B)
|
||||||
|
|
||||||
|
#define SDC_RX_FIFO_DATA_REG ((unsigned char *)0xFEC00310)
|
||||||
|
#define SDC_RX_FIFO_DATA_CNT_HI ((unsigned char *)0xFEC00312)
|
||||||
|
#define SDC_RX_FIFO_DATA_CNT_LO ((unsigned char *)0xFEC00313)
|
||||||
|
#define SDC_RX_FIFO_CTRL_REG ((unsigned char *)0xFEC00314)
|
||||||
|
|
||||||
|
#define SDC_TX_FIFO_DATA_REG ((unsigned char *)0xFEC00320)
|
||||||
|
#define SDC_TX_FIFO_CTRL_REG ((unsigned char *)0xFEC00324)
|
||||||
|
|
||||||
|
#endif
|
215
src/include/A2560K/sound_a2560k.h
Normal file
215
src/include/A2560K/sound_a2560k.h
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
/*
|
||||||
|
* Sound device register definitions for the A2560K
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SOUND_A2560K_H
|
||||||
|
#define __SOUND_A2560K_H
|
||||||
|
|
||||||
|
#define PSG_PORT ((volatile unsigned char *)0xFEC20100) /* Control register for the SN76489 */
|
||||||
|
#define PSG_INT_L_PORT ((volatile unsigned char *)0xFEC20110) /* Control register for the SN76489 */
|
||||||
|
#define PSG_INT_R_PORT ((volatile unsigned char *)0xFEC20120) /* Control register for the SN76489 */
|
||||||
|
#define PSG_INT_S_PORT ((volatile unsigned char *)0xFEC20130) /* Control register for the SN76489 */
|
||||||
|
#define OPL3_PORT ((volatile unsigned char *)0xFEC20200) /* Access port for the OPL3 */
|
||||||
|
#define OPM_EXT_BASE ((volatile unsigned char *)0xFEC20600) /* External OPM base address */
|
||||||
|
#define OPN2_EXT_BASE ((volatile unsigned char *)0xFEC20400) /* External OPN2 base address */
|
||||||
|
#define OPM_INT_BASE ((volatile unsigned char *)0xFEC20C00) /* Internal OPM base address */
|
||||||
|
#define OPN2_INT_BASE ((volatile unsigned char *)0xFEC20A00) /* Internal OPN2 base address */
|
||||||
|
#define CODEC ((volatile unsigned short *)0xFEC20E00) /* Control register for the CODEC */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A2560K supports two external, physical SID chips.
|
||||||
|
* It also implements the Gideon FPGA based SID in either stereo or mono (neutral) form
|
||||||
|
*
|
||||||
|
* $00C20800..$00C008FF - Extern Left SID
|
||||||
|
* $00C20900..$00C009FF - Extern Right SID
|
||||||
|
* $00C21000..$00C211FF - Internal SID Left
|
||||||
|
* $00C21200..$00C213FF - Internal SID Right
|
||||||
|
* $00C21400..$00C215FF - Internal SID Neutral
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* External SID Left Channel
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SID_EXT_L_V1_FREQ_LO ((unsigned char *)0xFEC20800)
|
||||||
|
#define SID_EXT_L_V1_FREQ_HI ((unsigned char *)0xFEC20801)
|
||||||
|
#define SID_EXT_L_V1_PW_LO ((unsigned char *)0xFEC20802)
|
||||||
|
#define SID_EXT_L_V1_PW_HI ((unsigned char *)0xFEC20803)
|
||||||
|
#define SID_EXT_L_V1_CTRL ((unsigned char *)0xFEC20804)
|
||||||
|
#define SID_EXT_L_V1_ATCK_DECY ((unsigned char *)0xFEC20805)
|
||||||
|
#define SID_EXT_L_V1_SSTN_RLSE ((unsigned char *)0xFEC20806)
|
||||||
|
#define SID_EXT_L_V2_FREQ_LO ((unsigned char *)0xFEC20807)
|
||||||
|
#define SID_EXT_L_V2_FREQ_HI ((unsigned char *)0xFEC20808)
|
||||||
|
#define SID_EXT_L_V2_PW_LO ((unsigned char *)0xFEC20809)
|
||||||
|
#define SID_EXT_L_V2_PW_HI ((unsigned char *)0xFEC2080A)
|
||||||
|
#define SID_EXT_L_V2_CTRL ((unsigned char *)0xFEC2080B)
|
||||||
|
#define SID_EXT_L_V2_ATCK_DECY ((unsigned char *)0xFEC2080C)
|
||||||
|
#define SID_EXT_L_V2_SSTN_RLSE ((unsigned char *)0xFEC2080D)
|
||||||
|
#define SID_EXT_L_V3_FREQ_LO ((unsigned char *)0xFEC2080E)
|
||||||
|
#define SID_EXT_L_V3_FREQ_HI ((unsigned char *)0xFEC2080F)
|
||||||
|
#define SID_EXT_L_V3_PW_LO ((unsigned char *)0xFEC20810)
|
||||||
|
#define SID_EXT_L_V3_PW_HI ((unsigned char *)0xFEC20811)
|
||||||
|
#define SID_EXT_L_V3_CTRL ((unsigned char *)0xFEC20812)
|
||||||
|
#define SID_EXT_L_V3_ATCK_DECY ((unsigned char *)0xFEC20813)
|
||||||
|
#define SID_EXT_L_V3_SSTN_RLSE ((unsigned char *)0xFEC20814)
|
||||||
|
#define SID_EXT_L_FC_LO ((unsigned char *)0xFEC20815)
|
||||||
|
#define SID_EXT_L_FC_HI ((unsigned char *)0xFEC20816)
|
||||||
|
#define SID_EXT_L_RES_FILT ((unsigned char *)0xFEC20817)
|
||||||
|
#define SID_EXT_L_MODE_VOL ((unsigned char *)0xFEC20818)
|
||||||
|
#define SID_EXT_L_POT_X ((unsigned char *)0xFEC20819)
|
||||||
|
#define SID_EXT_L_POT_Y ((unsigned char *)0xFEC2081A)
|
||||||
|
#define SID_EXT_L_OSC3_RND ((unsigned char *)0xFEC2081B)
|
||||||
|
#define SID_EXT_L_ENV3 ((unsigned char *)0xFEC2081C)
|
||||||
|
#define SID_EXT_L_NOT_USED0 ((unsigned char *)0xFEC2081D)
|
||||||
|
#define SID_EXT_L_NOT_USED1 ((unsigned char *)0xFEC2081E)
|
||||||
|
#define SID_EXT_L_NOT_USED2 ((unsigned char *)0xFEC2081F)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* External SID Right Channel
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SID_EXT_R_V1_FREQ_LO ((unsigned char *)0xFEC20900)
|
||||||
|
#define SID_EXT_R_V1_FREQ_HI ((unsigned char *)0xFEC20901)
|
||||||
|
#define SID_EXT_R_V1_PW_LO ((unsigned char *)0xFEC20902)
|
||||||
|
#define SID_EXT_R_V1_PW_HI ((unsigned char *)0xFEC20903)
|
||||||
|
#define SID_EXT_R_V1_CTRL ((unsigned char *)0xFEC20904)
|
||||||
|
#define SID_EXT_R_V1_ATCK_DECY ((unsigned char *)0xFEC20905)
|
||||||
|
#define SID_EXT_R_V1_SSTN_RLSE ((unsigned char *)0xFEC20906)
|
||||||
|
#define SID_EXT_R_V2_FREQ_LO ((unsigned char *)0xFEC20907)
|
||||||
|
#define SID_EXT_R_V2_FREQ_HI ((unsigned char *)0xFEC20908)
|
||||||
|
#define SID_EXT_R_V2_PW_LO ((unsigned char *)0xFEC20909)
|
||||||
|
#define SID_EXT_R_V2_PW_HI ((unsigned char *)0xFEC2090A)
|
||||||
|
#define SID_EXT_R_V2_CTRL ((unsigned char *)0xFEC2090B)
|
||||||
|
#define SID_EXT_R_V2_ATCK_DECY ((unsigned char *)0xFEC2090C)
|
||||||
|
#define SID_EXT_R_V2_SSTN_RLSE ((unsigned char *)0xFEC2090D)
|
||||||
|
#define SID_EXT_R_V3_FREQ_LO ((unsigned char *)0xFEC2090E)
|
||||||
|
#define SID_EXT_R_V3_FREQ_HI ((unsigned char *)0xFEC2090F)
|
||||||
|
#define SID_EXT_R_V3_PW_LO ((unsigned char *)0xFEC20910)
|
||||||
|
#define SID_EXT_R_V3_PW_HI ((unsigned char *)0xFEC20911)
|
||||||
|
#define SID_EXT_R_V3_CTRL ((unsigned char *)0xFEC20912)
|
||||||
|
#define SID_EXT_R_V3_ATCK_DECY ((unsigned char *)0xFEC20913)
|
||||||
|
#define SID_EXT_R_V3_SSTN_RLSE ((unsigned char *)0xFEC20914)
|
||||||
|
#define SID_EXT_R_FC_LO ((unsigned char *)0xFEC20915)
|
||||||
|
#define SID_EXT_R_FC_HI ((unsigned char *)0xFEC20916)
|
||||||
|
#define SID_EXT_R_RES_FILT ((unsigned char *)0xFEC20917)
|
||||||
|
#define SID_EXT_R_MODE_VOL ((unsigned char *)0xFEC20918)
|
||||||
|
#define SID_EXT_R_POT_X ((unsigned char *)0xFEC20919)
|
||||||
|
#define SID_EXT_R_POT_Y ((unsigned char *)0xFEC2091A)
|
||||||
|
#define SID_EXT_R_OSC3_RND ((unsigned char *)0xFEC2091B)
|
||||||
|
#define SID_EXT_R_ENV3 ((unsigned char *)0xFEC2091C)
|
||||||
|
#define SID_EXT_R_NOT_USED0 ((unsigned char *)0xFEC2091D)
|
||||||
|
#define SID_EXT_R_NOT_USED1 ((unsigned char *)0xFEC2091E)
|
||||||
|
#define SID_EXT_R_NOT_USED2 ((unsigned char *)0xFEC2091F)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal SID Left Channel
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SID_INT_L_V1_FREQ_LO ((unsigned char *)0xFEC21000)
|
||||||
|
#define SID_INT_L_V1_FREQ_HI ((unsigned char *)0xFEC21001)
|
||||||
|
#define SID_INT_L_V1_PW_LO ((unsigned char *)0xFEC21002)
|
||||||
|
#define SID_INT_L_V1_PW_HI ((unsigned char *)0xFEC21003)
|
||||||
|
#define SID_INT_L_V1_CTRL ((unsigned char *)0xFEC21004)
|
||||||
|
#define SID_INT_L_V1_ATCK_DECY ((unsigned char *)0xFEC21005)
|
||||||
|
#define SID_INT_L_V1_SSTN_RLSE ((unsigned char *)0xFEC21006)
|
||||||
|
#define SID_INT_L_V2_FREQ_LO ((unsigned char *)0xFEC21007)
|
||||||
|
#define SID_INT_L_V2_FREQ_HI ((unsigned char *)0xFEC21008)
|
||||||
|
#define SID_INT_L_V2_PW_LO ((unsigned char *)0xFEC21009)
|
||||||
|
#define SID_INT_L_V2_PW_HI ((unsigned char *)0xFEC2100A)
|
||||||
|
#define SID_INT_L_V2_CTRL ((unsigned char *)0xFEC2100B)
|
||||||
|
#define SID_INT_L_V2_ATCK_DECY ((unsigned char *)0xFEC2100C)
|
||||||
|
#define SID_INT_L_V2_SSTN_RLSE ((unsigned char *)0xFEC2100D)
|
||||||
|
#define SID_INT_L_V3_FREQ_LO ((unsigned char *)0xFEC2100E)
|
||||||
|
#define SID_INT_L_V3_FREQ_HI ((unsigned char *)0xFEC2100F)
|
||||||
|
#define SID_INT_L_V3_PW_LO ((unsigned char *)0xFEC21010)
|
||||||
|
#define SID_INT_L_V3_PW_HI ((unsigned char *)0xFEC21011)
|
||||||
|
#define SID_INT_L_V3_CTRL ((unsigned char *)0xFEC21012)
|
||||||
|
#define SID_INT_L_V3_ATCK_DECY ((unsigned char *)0xFEC21013)
|
||||||
|
#define SID_INT_L_V3_SSTN_RLSE ((unsigned char *)0xFEC21014)
|
||||||
|
#define SID_INT_L_FC_LO ((unsigned char *)0xFEC21015)
|
||||||
|
#define SID_INT_L_FC_HI ((unsigned char *)0xFEC21016)
|
||||||
|
#define SID_INT_L_RES_FILT ((unsigned char *)0xFEC21017)
|
||||||
|
#define SID_INT_L_MODE_VOL ((unsigned char *)0xFEC21018)
|
||||||
|
#define SID_INT_L_POT_X ((unsigned char *)0xFEC21019)
|
||||||
|
#define SID_INT_L_POT_Y ((unsigned char *)0xFEC2101A)
|
||||||
|
#define SID_INT_L_OSC3_RND ((unsigned char *)0xFEC2101B)
|
||||||
|
#define SID_INT_L_ENV3 ((unsigned char *)0xFEC2101C)
|
||||||
|
#define SID_INT_L_NOT_USED0 ((unsigned char *)0xFEC2101D)
|
||||||
|
#define SID_INT_L_NOT_USED1 ((unsigned char *)0xFEC2101E)
|
||||||
|
#define SID_INT_L_NOT_USED2 ((unsigned char *)0xFEC2101F)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal SID Right Channel
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SID_INT_R_V1_FREQ_LO ((unsigned char *)0xFEC21200)
|
||||||
|
#define SID_INT_R_V1_FREQ_HI ((unsigned char *)0xFEC21201)
|
||||||
|
#define SID_INT_R_V1_PW_LO ((unsigned char *)0xFEC21202)
|
||||||
|
#define SID_INT_R_V1_PW_HI ((unsigned char *)0xFEC21203)
|
||||||
|
#define SID_INT_R_V1_CTRL ((unsigned char *)0xFEC21204)
|
||||||
|
#define SID_INT_R_V1_ATCK_DECY ((unsigned char *)0xFEC21205)
|
||||||
|
#define SID_INT_R_V1_SSTN_RLSE ((unsigned char *)0xFEC21206)
|
||||||
|
#define SID_INT_R_V2_FREQ_LO ((unsigned char *)0xFEC21207)
|
||||||
|
#define SID_INT_R_V2_FREQ_HI ((unsigned char *)0xFEC21208)
|
||||||
|
#define SID_INT_R_V2_PW_LO ((unsigned char *)0xFEC21209)
|
||||||
|
#define SID_INT_R_V2_PW_HI ((unsigned char *)0xFEC2120A)
|
||||||
|
#define SID_INT_R_V2_CTRL ((unsigned char *)0xFEC2120B)
|
||||||
|
#define SID_INT_R_V2_ATCK_DECY ((unsigned char *)0xFEC2120C)
|
||||||
|
#define SID_INT_R_V2_SSTN_RLSE ((unsigned char *)0xFEC2120D)
|
||||||
|
#define SID_INT_R_V3_FREQ_LO ((unsigned char *)0xFEC2120E)
|
||||||
|
#define SID_INT_R_V3_FREQ_HI ((unsigned char *)0xFEC2120F)
|
||||||
|
#define SID_INT_R_V3_PW_LO ((unsigned char *)0xFEC21210)
|
||||||
|
#define SID_INT_R_V3_PW_HI ((unsigned char *)0xFEC21211)
|
||||||
|
#define SID_INT_R_V3_CTRL ((unsigned char *)0xFEC21212)
|
||||||
|
#define SID_INT_R_V3_ATCK_DECY ((unsigned char *)0xFEC21213)
|
||||||
|
#define SID_INT_R_V3_SSTN_RLSE ((unsigned char *)0xFEC21214)
|
||||||
|
#define SID_INT_R_FC_LO ((unsigned char *)0xFEC21215)
|
||||||
|
#define SID_INT_R_FC_HI ((unsigned char *)0xFEC21216)
|
||||||
|
#define SID_INT_R_RES_FILT ((unsigned char *)0xFEC21217)
|
||||||
|
#define SID_INT_R_MODE_VOL ((unsigned char *)0xFEC21218)
|
||||||
|
#define SID_INT_R_POT_X ((unsigned char *)0xFEC21219)
|
||||||
|
#define SID_INT_R_POT_Y ((unsigned char *)0xFEC2121A)
|
||||||
|
#define SID_INT_R_OSC3_RND ((unsigned char *)0xFEC2121B)
|
||||||
|
#define SID_INT_R_ENV3 ((unsigned char *)0xFEC2121C)
|
||||||
|
#define SID_INT_R_NOT_USED0 ((unsigned char *)0xFEC2121D)
|
||||||
|
#define SID_INT_R_NOT_USED1 ((unsigned char *)0xFEC2121E)
|
||||||
|
#define SID_INT_R_NOT_USED2 ((unsigned char *)0xFEC2121F)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal SID Neutral Channel - When writting here, the value is written in R and L Channel at the same time
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SID_INT_N_V1_FREQ_LO ((unsigned char *)0xFEC41200)
|
||||||
|
#define SID_INT_N_V1_FREQ_HI ((unsigned char *)0xFEC41201)
|
||||||
|
#define SID_INT_N_V1_PW_LO ((unsigned char *)0xFEC41202)
|
||||||
|
#define SID_INT_N_V1_PW_HI ((unsigned char *)0xFEC41203)
|
||||||
|
#define SID_INT_N_V1_CTRL ((unsigned char *)0xFEC41204)
|
||||||
|
#define SID_INT_N_V1_ATCK_DECY ((unsigned char *)0xFEC41205)
|
||||||
|
#define SID_INT_N_V1_SSTN_RLSE ((unsigned char *)0xFEC41206)
|
||||||
|
#define SID_INT_N_V2_FREQ_LO ((unsigned char *)0xFEC41207)
|
||||||
|
#define SID_INT_N_V2_FREQ_HI ((unsigned char *)0xFEC41208)
|
||||||
|
#define SID_INT_N_V2_PW_LO ((unsigned char *)0xFEC41209)
|
||||||
|
#define SID_INT_N_V2_PW_HI ((unsigned char *)0xFEC4120A)
|
||||||
|
#define SID_INT_N_V2_CTRL ((unsigned char *)0xFEC4120B)
|
||||||
|
#define SID_INT_N_V2_ATCK_DECY ((unsigned char *)0xFEC4120C)
|
||||||
|
#define SID_INT_N_V2_SSTN_RLSE ((unsigned char *)0xFEC4120D)
|
||||||
|
#define SID_INT_N_V3_FREQ_LO ((unsigned char *)0xFEC4120E)
|
||||||
|
#define SID_INT_N_V3_FREQ_HI ((unsigned char *)0xFEC4120F)
|
||||||
|
#define SID_INT_N_V3_PW_LO ((unsigned char *)0xFEC41210)
|
||||||
|
#define SID_INT_N_V3_PW_HI ((unsigned char *)0xFEC41211)
|
||||||
|
#define SID_INT_N_V3_CTRL ((unsigned char *)0xFEC41212)
|
||||||
|
#define SID_INT_N_V3_ATCK_DECY ((unsigned char *)0xFEC41213)
|
||||||
|
#define SID_INT_N_V3_SSTN_RLSE ((unsigned char *)0xFEC41214)
|
||||||
|
#define SID_INT_N_FC_LO ((unsigned char *)0xFEC41215)
|
||||||
|
#define SID_INT_N_FC_HI ((unsigned char *)0xFEC41216)
|
||||||
|
#define SID_INT_N_RES_FILT ((unsigned char *)0xFEC41217)
|
||||||
|
#define SID_INT_N_MODE_VOL ((unsigned char *)0xFEC41218)
|
||||||
|
#define SID_INT_N_POT_X ((unsigned char *)0xFEC41219)
|
||||||
|
#define SID_INT_N_POT_Y ((unsigned char *)0xFEC4121A)
|
||||||
|
#define SID_INT_N_OSC3_RND ((unsigned char *)0xFEC4121B)
|
||||||
|
#define SID_INT_N_ENV3 ((unsigned char *)0xFEC4121C)
|
||||||
|
#define SID_INT_N_NOT_USED0 ((unsigned char *)0xFEC4121D)
|
||||||
|
#define SID_INT_N_NOT_USED1 ((unsigned char *)0xFEC4121E)
|
||||||
|
#define SID_INT_N_NOT_USED2 ((unsigned char *)0xFEC4121F)
|
||||||
|
|
||||||
|
#endif
|
64
src/include/A2560K/timers_a2560k.h
Normal file
64
src/include/A2560K/timers_a2560k.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/**
|
||||||
|
* @file timers_a2560k.h
|
||||||
|
*
|
||||||
|
* Define timer registers on the A2560K
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __A2560K_TIMERS_H
|
||||||
|
#define __A2560K_TIMERS_H
|
||||||
|
|
||||||
|
/** Timer control register 0: timers 0, 1, and 2 */
|
||||||
|
#define TIMER_TCR0 ((unsigned long *)0xFEC00200)
|
||||||
|
#define TCR_ENABLE_0 0x00000001 /** Enable counter 0 */
|
||||||
|
#define TCR_CLEAR_0 0x00000002 /** Master clear of counter 0 */
|
||||||
|
#define TCR_LOAD_0 0x00000004 /** Master load of counter 0 */
|
||||||
|
#define TCR_CNTUP_0 0x00000008 /** Counter 0 Count up if 1, count down if 0 */
|
||||||
|
#define TCR_INE_0 0x00000080 /** Interrupt enable for counter 0 */
|
||||||
|
|
||||||
|
#define TCR_ENABLE_1 0x00000100 /** Enable counter 1 */
|
||||||
|
#define TCR_CLEAR_1 0x00000200 /** Master clear of counter 1 */
|
||||||
|
#define TCR_LOAD_1 0x00000400 /** Master load of counter 1 */
|
||||||
|
#define TCR_CNTUP_1 0x00000800 /** Counter 1 Count up if 1, count down if 0 */
|
||||||
|
#define TCR_INE_1 0x00008000 /** Interrupt enable for counter 1 */
|
||||||
|
|
||||||
|
#define TCR_ENABLE_2 0x00010000 /** Enable counter 2 */
|
||||||
|
#define TCR_CLEAR_2 0x00020000 /** Master clear of counter 2 */
|
||||||
|
#define TCR_LOAD_2 0x00040000 /** Master load of counter 2 */
|
||||||
|
#define TCR_CNTUP_2 0x00080000 /** Counter 2 Count up if 1, count down if 0 */
|
||||||
|
#define TCR_INE_2 0x00800000 /** Interrupt enable for counter 2 */
|
||||||
|
|
||||||
|
/** Timer control register 1: timers 3 and 4 */
|
||||||
|
#define TIMER_TCR1 ((unsigned long *)0xFEC00204)
|
||||||
|
#define TCR_ENABLE_3 0x00000001 /** Enable counter 3 */
|
||||||
|
#define TCR_CLEAR_3 0x00000002 /** Master clear of counter 3 */
|
||||||
|
#define TCR_LOAD_3 0x00000004 /** Master load of counter 3 */
|
||||||
|
#define TCR_CNTUP_3 0x00000008 /** Counter 3 Count up if 1, count down if 0 */
|
||||||
|
#define TCR_RECLR_3 0x00000010 /** Enable reclear of timer 3 */
|
||||||
|
#define TCR_RELOAD_3 0x00000020 /** Enable reload of timer 3 */
|
||||||
|
#define TCR_INE_3 0x00000080 /** Interrupt enable for counter 3 */
|
||||||
|
|
||||||
|
#define TCR_ENABLE_4 0x00000100 /** Enable counter 4 */
|
||||||
|
#define TCR_CLEAR_4 0x00000200 /** Master clear of counter 4 */
|
||||||
|
#define TCR_LOAD_4 0x00000400 /** Master load of counter 4 */
|
||||||
|
#define TCR_CNTUP_4 0x00000800 /** Counter 4 Count up if 1, count down if 0 */
|
||||||
|
#define TCR_RECLR_4 0x00001000 /** Enable reclear of timer 4 */
|
||||||
|
#define TCR_RELOAD_4 0x00002000 /** Enable reload of timer 4 */
|
||||||
|
#define TCR_INE_4 0x00008000 /** Interrupt enable for counter 4 */
|
||||||
|
|
||||||
|
#define TCR_STAT_EQ0 0x08000000 /** Read only: timer 0 is equal to its comparison value */
|
||||||
|
#define TCR_STAT_EQ1 0x10000000 /** Read only: timer 1 is equal to its comparison value */
|
||||||
|
#define TCR_STAT_EQ2 0x20000000 /** Read only: timer 2 is equal to its comparison value */
|
||||||
|
#define TCR_STAT_EQ3 0x40000000 /** Read only: timer 3 is equal to its comparison value */
|
||||||
|
|
||||||
|
#define TIMER_VALUE_0 ((unsigned long *)0xFEC00208)
|
||||||
|
#define TIMER_COMPARE_0 ((unsigned long *)0xFEC0020C)
|
||||||
|
#define TIMER_VALUE_1 ((unsigned long *)0xFEC00210)
|
||||||
|
#define TIMER_COMPARE_1 ((unsigned long *)0xFEC00214)
|
||||||
|
#define TIMER_VALUE_2 ((unsigned long *)0xFEC00218)
|
||||||
|
#define TIMER_COMPARE_2 ((unsigned long *)0xFEC0021C)
|
||||||
|
#define TIMER_VALUE_3 ((unsigned long *)0xFEC00220)
|
||||||
|
#define TIMER_COMPARE_3 ((unsigned long *)0xFEC00224)
|
||||||
|
#define TIMER_VALUE_4 ((unsigned long *)0xFEC00228)
|
||||||
|
#define TIMER_COMPARE_4 ((unsigned long *)0xFEC0022C)
|
||||||
|
|
||||||
|
#endif
|
52
src/include/A2560K/vky_chan_a.h
Normal file
52
src/include/A2560K/vky_chan_a.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/**
|
||||||
|
* @file vky_chan_a.h
|
||||||
|
*
|
||||||
|
* Define register addresses needed for A2560K channel A text driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VKY_CHAN_A_H
|
||||||
|
#define __VKY_CHAN_A_H
|
||||||
|
|
||||||
|
/** Master Control Register for Channel A, and its supported bits */
|
||||||
|
#define VKY3_A_MCR ((volatile unsigned long *)0xFEC40000)
|
||||||
|
#define VKY3_A_MCR_TEXT 0x00000001 /**< Text mode enable bit */
|
||||||
|
#define VKY3_A_MCR_SLEEP 0x00040000 /**< Monitor sleep (synch disable) bit */
|
||||||
|
#define VKY3_A_1024x768 0x00000800 /**< Bit to select 1024x768 screen resolution */
|
||||||
|
#define VKY3_A_HIRES 0x40000000 /**< Bit to indicate on read if hi-res display is requested on the DIP switches */
|
||||||
|
#define VKY3_A_CLK40 0x80000000 /**< Indicate if PLL is 25MHz (0) or 40MHz (1) */
|
||||||
|
|
||||||
|
/** Border control register for Channel A */
|
||||||
|
#define VKY3_A_BCR ((volatile unsigned long *)0xFEC40004)
|
||||||
|
#define VKY3_A_BCR_ENABLE 0x00000001 /**< Bit to enable the display of the border */
|
||||||
|
|
||||||
|
/** Border color register for Channel A */
|
||||||
|
#define VKY3_A_BRDCOLOR ((volatile unsigned long *)0xFEC40008)
|
||||||
|
|
||||||
|
/** Cursor Control Register for Channel A */
|
||||||
|
#define VKY3_A_CCR ((volatile unsigned long *)0xFEC40010)
|
||||||
|
#define VKY3_A_CCR_ENABLE 0x00000001 /**< Bit to enable the display of the cursor */
|
||||||
|
#define VKY3_A_CCR_RATE0 0x00000002 /**< Bit0 to specify the blink rate */
|
||||||
|
#define VKY3_A_CCR_RATE1 0x00000004 /**< Bit1 to specify the blink rate */
|
||||||
|
|
||||||
|
/** Cursor Position Register for Channel A */
|
||||||
|
#define VKY3_A_CPR ((volatile unsigned long *)0xFEC40014)
|
||||||
|
|
||||||
|
/** Font Manager Registers for Channel A */
|
||||||
|
#define VKY3_A_FM0 ((volatile unsigned long *)0xFEC40020)
|
||||||
|
#define VKY3_A_FM1 ((volatile unsigned long *)0xFEC40024)
|
||||||
|
|
||||||
|
/** Font memory block for Channel A */
|
||||||
|
#define VKY3_A_FONT_MEMORY ((volatile unsigned char *)0xFEC48000)
|
||||||
|
|
||||||
|
/** Text Matrix for Channel A */
|
||||||
|
#define VKY3_A_TEXT_MATRIX ((volatile unsigned char *)0xFEC60000)
|
||||||
|
|
||||||
|
/** Color Matrix for Channel A */
|
||||||
|
#define VKY3_A_COLOR_MATRIX ((volatile unsigned char *)0xFEC68000)
|
||||||
|
|
||||||
|
/* Text Color LUTs for Channel A */
|
||||||
|
#define VKY3_A_LUT_SIZE 16
|
||||||
|
#define VKY3_A_TEXT_LUT_FG ((volatile unsigned long *)0xFEC6C400) /**< Text foreground color look up table for channel A */
|
||||||
|
#define VKY3_A_TEXT_LUT_BG ((volatile unsigned long *)0xFEC6C440) /**< Text background color look up table for channel A */
|
||||||
|
|
||||||
|
#endif
|
57
src/include/A2560K/vky_chan_b.h
Normal file
57
src/include/A2560K/vky_chan_b.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/**
|
||||||
|
* @file vky_chan_b.h
|
||||||
|
*
|
||||||
|
* Define register addresses needed for A2560K channel B text driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VKY_CHAN_B_H
|
||||||
|
#define __VKY_CHAN_B_H
|
||||||
|
|
||||||
|
/** Master Control Register for Channel B, and its supported bits */
|
||||||
|
#define VKY3_B_MCR ((volatile unsigned long *)0xFEC80000)
|
||||||
|
#define VKY3_B_MCR_TEXT 0x00000001 /**< Text mode enable bit */
|
||||||
|
#define VKY3_B_MCR_TXT_OVR 0x00000002 /**< Text overlay enable bit */
|
||||||
|
#define VKY3_B_MCR_GRAPHICS 0x00000004 /**< Graphics mode enable bit */
|
||||||
|
#define VKY3_B_MCR_BITMAP 0x00000008 /**< Bitmap engineg enable bit */
|
||||||
|
#define VKY3_B_MCR_TILE 0x00000010 /**< Tile engine enable bit */
|
||||||
|
#define VKY3_B_MCR_SPRITE 0x00000020 /**< Sprite engine enable bit */
|
||||||
|
#define VKY3_B_MCR_BLANK 0x00000080 /**< Disable display engine enable bit */
|
||||||
|
#define VKY3_B_MODE0 0x00000100 /**< Video Mode Bit 0 */
|
||||||
|
#define VKY3_B_MODE1 0x00000200 /**< Video Mode Bit 1 */
|
||||||
|
#define VKY3_B_DOUBLE 0x00000400 /**< Pixel Double Enable bit */
|
||||||
|
#define VKY3_B_HIRES 0x40000000 /**< DIP switch for hires mode */
|
||||||
|
#define VKY3_B_PLL 0x00000800 /**< Controls dot clock */
|
||||||
|
#define VKY3_B_MCR_SLEEP 0x00040000 /**< Monitor sleep (synch disable) bit */
|
||||||
|
#define VKY3_B_CLK40 0x80000000 /**< Indicate if PLL is 25MHz (0) or 40MHz (1) */
|
||||||
|
|
||||||
|
/** Border control register for Channel B */
|
||||||
|
#define VKY3_B_BCR ((volatile unsigned long *)0xFEC80004)
|
||||||
|
#define VKY3_B_BCR_ENABLE 0x00000001 /**< Bit to enable the display of the border */
|
||||||
|
|
||||||
|
/** Border color register for Channel B */
|
||||||
|
#define VKY3_B_BRDCOLOR ((volatile unsigned long *)0xFEC80008)
|
||||||
|
|
||||||
|
/** Cursor Control Register for Channel B */
|
||||||
|
#define VKY3_B_CCR ((volatile unsigned long *)0xFEC80010)
|
||||||
|
#define VKY3_B_CCR_ENABLE 0x00000001 /**< Bit to enable the display of the cursor */
|
||||||
|
#define VKY3_B_CCR_RATE0 0x00000002 /**< Bit0 to specify the blink rate */
|
||||||
|
#define VKY3_B_CCR_RATE1 0x00000004 /**< Bit1 to specify the blink rate */
|
||||||
|
|
||||||
|
/** Cursor Position Register for Channel B */
|
||||||
|
#define VKY3_B_CPR ((volatile unsigned long *)0xFEC80014)
|
||||||
|
|
||||||
|
/** Font memory block for Channel B */
|
||||||
|
#define VKY3_B_FONT_MEMORY ((volatile unsigned char *)0xFEC88000)
|
||||||
|
|
||||||
|
/** Text Matrix for Channel B */
|
||||||
|
#define VKY3_B_TEXT_MATRIX ((volatile unsigned char *)0xFECA0000)
|
||||||
|
|
||||||
|
/** Color Matrix for Channel B */
|
||||||
|
#define VKY3_B_COLOR_MATRIX ((volatile unsigned char *)0xFECA8000)
|
||||||
|
|
||||||
|
/* Text Color LUTs for Channel B */
|
||||||
|
#define VKY3_B_LUT_SIZE 16
|
||||||
|
#define VKY3_B_TEXT_LUT_FG ((volatile unsigned long *)0xFECAC400) /**< Text foreground color look up table for channel B */
|
||||||
|
#define VKY3_B_TEXT_LUT_BG ((volatile unsigned long *)0xFECAC440) /**< Text background color look up table for channel B */
|
||||||
|
|
||||||
|
#endif
|
103
src/include/A2560U/VICKYIII_a2560u.h
Normal file
103
src/include/A2560U/VICKYIII_a2560u.h
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Registers and memory blocks for VICKY III on the A2560U and A2560U+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VICKYIII_General_H
|
||||||
|
#define __VICKYIII_General_H
|
||||||
|
|
||||||
|
#define VKY3_TEXT_LUT_SIZE 16
|
||||||
|
#define VKY3_TEXT_LUT_FG ((volatile unsigned long *)0x00B6C400) /**< Text foreground color look up table */
|
||||||
|
#define VKY3_TEXT_LUT_BG ((volatile unsigned long *)0x00B6C440) /**< Text background color look up table */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Screen Channel A
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MasterControlReg_A ((volatile unsigned long *)0x00B40000)
|
||||||
|
#define VKY3_MCR_TEXT_EN 0x00000001 /* Text Mode Enable */
|
||||||
|
#define VKY3_MCR_TEXT_OVRLY 0x00000002 /* Text Mode overlay */
|
||||||
|
#define VKY3_MCR_GRAPH_EN 0x00000004 /* Graphic Mode Enable */
|
||||||
|
#define VKY3_MCR_BITMAP_EN 0x00000008 /* Bitmap Engine Enable */
|
||||||
|
#define VKY3_MCR_RESOLUTION_MASK 0x00000300 /* Resolution - 00: 640x480, 01:800x600, 10: 1024x768, 11: 640x400 */
|
||||||
|
#define VKY3_MCR_640x480 0x00000000
|
||||||
|
#define VKY3_MCR_800x600 0x00000100
|
||||||
|
#define VKY3_MCR_1024x768 0x00000200
|
||||||
|
#define VKY3_MCR_640x400 0x00000300
|
||||||
|
#define VKY3_MCR_DOUBLE_EN 0x00000400 /* Doubling Pixel */
|
||||||
|
#define VKY3_MCR_RES_MASK (VKY3_MCR_800x600|VKY3_MCR_1024x768|VKY3_MCR_DOUBLE_EN) /* Bits used to set the resolution */
|
||||||
|
#define VKY3_MCR_GAMMA_EN 0x00010000 /* GAMMA Enable */
|
||||||
|
#define VKY3_MCR_MANUAL_GAMMA_EN 0x00020000 /* Enable Manual GAMMA Enable */
|
||||||
|
#define VKY3_MCR_BLANK_EN 0x00040000 /* Turn OFF sync (to monitor in sleep mode) */
|
||||||
|
|
||||||
|
/* Access to DIP switch information (read only) */
|
||||||
|
#define VKY3_DIP_REG ((volatile unsigned short *)0x00B40002)
|
||||||
|
/* Bits 0 - 12: Master Control Register data */
|
||||||
|
#define VKY3_DIP_GAMMA 0x2000 /* DIP switch indication for Gamma correction */
|
||||||
|
#define VKY3_DIP_HIRES 0x4000 /* DIP switch for high resolution mode */
|
||||||
|
#define VKY3_PLL_ACTIVE_CLK 0x8000 /* Active Clock --- 0: 25.175Mhz, 1: 40Mhz */
|
||||||
|
|
||||||
|
#define BorderControlReg ((volatile unsigned long *)0x00B40004)
|
||||||
|
#define VKY3_BRDR_EN 0x00000001 /* Border Enable */
|
||||||
|
#define VKY3_X_SCROLL_MASK 0x00000070 /* X Scroll */
|
||||||
|
#define VKY3_X_SIZE_MASK 0x00003f00 /* X Size */
|
||||||
|
#define VKY3_Y_SIZE_MASK 0x003f0000 /* Y Size */
|
||||||
|
|
||||||
|
#define BorderColorReg ((volatile unsigned long *)0x00B40008)
|
||||||
|
#define BackGroundControlReg_A ((volatile unsigned long *)0x00B4000C)
|
||||||
|
#define CursorControlReg ((volatile unsigned long *)0x00B40010)
|
||||||
|
#define CursorPositionReg ((volatile unsigned long *)0x00B40014)
|
||||||
|
|
||||||
|
#define LineInterrupt0_A ((volatile unsigned short *)0x00B40018)
|
||||||
|
#define LineInterrupt1_A ((volatile unsigned short *)0x00B4001A)
|
||||||
|
#define LineInterrupt2_A ((volatile unsigned short *)0x00B4001C)
|
||||||
|
#define LineInterrupt3_A ((volatile unsigned short *)0x00B4001E)
|
||||||
|
|
||||||
|
#define MousePointer_Mem_A ((volatile unsigned short *)0x00B40400)
|
||||||
|
#define MousePtr_A_CTRL_Reg ((volatile unsigned short *)0x00B40C00)
|
||||||
|
#define MousePtr_En 0x0001
|
||||||
|
|
||||||
|
#define MousePtr_A_X_Pos ((volatile unsigned short *)0x00B40C02)
|
||||||
|
#define MousePtr_A_Y_Pos ((volatile unsigned short *)0x00B40C04)
|
||||||
|
#define MousePtr_A_Mouse0 ((volatile unsigned short *)0x00B40C0A)
|
||||||
|
#define MousePtr_A_Mouse1 ((volatile unsigned short *)0x00B40C0C)
|
||||||
|
#define MousePtr_A_Mouse2 ((volatile unsigned short *)0x00B40C0E)
|
||||||
|
|
||||||
|
#define ScreenText_A ((volatile char *)0x00B60000) /* Text matrix */
|
||||||
|
#define ColorText_A ((volatile unsigned char *)0x00B68000) /* Color matrix */
|
||||||
|
#define FG_CLUT_A ((volatile unsigned short *)0x00B6C400) /* Foreground LUT */
|
||||||
|
#define BG_CLUT_A ((volatile unsigned short *)0x00B6C440) /* Background LUT */
|
||||||
|
|
||||||
|
#define BM0_Control_Reg ((volatile unsigned long *)0x00B40100)
|
||||||
|
#define BM0_Addy_Pointer_Reg ((volatile unsigned long *)0x00B40104)
|
||||||
|
|
||||||
|
#define Sprite_0_CTRL ((volatile unsigned short *)0x00B41000)
|
||||||
|
#define Sprite_0_ADDY_HI ((volatile unsigned short *)0x00B41002)
|
||||||
|
#define Sprite_0_POS_X ((volatile unsigned short *)0x00B41004)
|
||||||
|
#define Sprite_0_POS_Y ((volatile unsigned short *)0x00B41006)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Color lookup tables
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LUT_0 ((volatile unsigned char *)0x00B42000)
|
||||||
|
#define LUT_1 ((volatile unsigned char *)0x00B42400)
|
||||||
|
#define LUT_2 ((volatile unsigned char *)0x00B42800)
|
||||||
|
#define LUT_3 ((volatile unsigned char *)0x00B42C00)
|
||||||
|
#define LUT_4 ((volatile unsigned char *)0x00B43000)
|
||||||
|
#define LUT_5 ((volatile unsigned char *)0x00B43400)
|
||||||
|
#define LUT_6 ((volatile unsigned char *)0x00B43800)
|
||||||
|
#define LUT_7 ((volatile unsigned char *)0x00B43C00)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Text mode font memory
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define VICKY_TXT_FONT_A ((volatile unsigned char *)0x00B48000) /* $00C48000..$00C48FFF - FONT MEMORY Channel A */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Location of VRAM
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define VRAM_Bank0 ((volatile unsigned char *)0x00C00000)
|
||||||
|
|
||||||
|
#endif
|
66
src/include/A2560U/gabe_a2560u.h
Normal file
66
src/include/A2560U/gabe_a2560u.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
* @file gabe_a2560u.h
|
||||||
|
*
|
||||||
|
* Define miscellaneous GABE registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GABE_A2560U_H
|
||||||
|
#define __GABE_A2560U_H
|
||||||
|
|
||||||
|
#define GABE_CTRL_REG ((volatile unsigned short *)0x00B00000)
|
||||||
|
#define POWER_ON_LED 0x0001
|
||||||
|
#define SDCARD_LED 0x0002
|
||||||
|
#define BUZZER_CONTROL 0x0010
|
||||||
|
#define MANUAL_RESET 0x8000 // Make sure the word "DEAD" is written in GABE_RESET_ID
|
||||||
|
|
||||||
|
#define GABE_RESET_ID ((volatile unsigned short *)0x00B00002)
|
||||||
|
#define GABE_LFSR_REG0 ((volatile unsigned short *)0x00B00004)
|
||||||
|
#define GABE_LFSR_REG1 ((volatile unsigned short *)0x00B00006)
|
||||||
|
|
||||||
|
#define RGB_LED_L ((volatile unsigned short *)0x00B00008) // Writing Only - A2560K Only - 0x__RR
|
||||||
|
#define RGB_LED_H ((volatile unsigned short *)0x00B0000A) // Writing Only - A2560K Only - 0xGGBB
|
||||||
|
|
||||||
|
#define GABE_LFSR_DATA ((volatile unsigned short *)0x00B00008) // Read Only
|
||||||
|
#define GABE_LFSR_STAT ((volatile unsigned short *)0x00B0000A) // Read Only
|
||||||
|
#define GABE_MACHINE_ID ((volatile unsigned short *)0x00B0000C) // Machine ID - Read Only
|
||||||
|
#define GABE_MACH_ID_MASK 0x0003 // 1001 = A2560U and U+
|
||||||
|
#define GABE_MEMORY_BANKS 0x00C0 // 10 = 2 MB, 11 = 4 MB
|
||||||
|
#define GABE_CPU_SPEED 0x0F00
|
||||||
|
#define GABE_CPU_ID 0xF000 // 0000 = MC68SEC000 @ 20MHz
|
||||||
|
|
||||||
|
#define GAVIN_ATARI_JOYSTICK ((volatile unsigned short *)0x00B00500)
|
||||||
|
#define JOY1_UP 0x0001
|
||||||
|
#define JOY1_DOWN 0x0002
|
||||||
|
#define JOY1_LEFT 0x0004
|
||||||
|
#define JOY1_RIGHT 0x0008
|
||||||
|
#define JOY1_BTN0 0x0010
|
||||||
|
#define JOY1_BTN1 0x0040
|
||||||
|
#define JOY1_BTN2 0x0080
|
||||||
|
#define JOY2_UP 0x0100
|
||||||
|
#define JOY2_DOWN 0x0200
|
||||||
|
#define JOY2_LEFT 0x0400
|
||||||
|
#define JOY2_RIGHT 0x0800
|
||||||
|
#define JOY2_BTN0 0x1000
|
||||||
|
#define JOY2_BTN1 0x4000
|
||||||
|
#define JOY2_BTN2 0x8000
|
||||||
|
|
||||||
|
#define FPGA_DATE_YEAR ((volatile unsigned short *)0x00B40030) // YYYY
|
||||||
|
#define FPGA_DATE_MONTHDAY ((volatile unsigned short *)0x00B40032) // MMDD
|
||||||
|
|
||||||
|
#define PCB_REV_1 ((volatile unsigned short *)0x00B40034) // Null terminated string describing the PCB
|
||||||
|
#define PCB_REV_2 ((volatile unsigned short *)0x00B40036)
|
||||||
|
|
||||||
|
#define FPGA_SUBVER ((volatile unsigned short *)0x00B40038)
|
||||||
|
#define FPGA_VER ((volatile unsigned short *)0x00B4003A)
|
||||||
|
#define FPGA_MODEL_L ((volatile unsigned short *)0x00B4003C)
|
||||||
|
#define FPGA_MODEL_H ((volatile unsigned short *)0x00B4003E)
|
||||||
|
|
||||||
|
#define GABE_CHIP_SUBREV ((volatile unsigned short *)0x00B0000E)
|
||||||
|
#define GABE_CHIP_VERSION ((volatile unsigned short *)0x00B00010)
|
||||||
|
#define GABE_CHIP_NUMBER ((volatile unsigned short *)0x00B00012)
|
||||||
|
|
||||||
|
#define GABE_DIP_REG ((volatile unsigned short *)0x00B00518)
|
||||||
|
#define GABE_DIP_BOOT_MASK 0x0003 /* Mask for the boot mode: */
|
||||||
|
#define GABE_DIP_USER_MASK 0x0300 /* Mask for the user switches: */
|
||||||
|
|
||||||
|
#endif
|
18
src/include/A2560U/pata_a2560u.h
Normal file
18
src/include/A2560U/pata_a2560u.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Definitions to access the PATA port on the A2560U and A2560U+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PATA_A2560U_H
|
||||||
|
#define __PATA_A2560U_H
|
||||||
|
|
||||||
|
#define PATA_DATA_16 ((volatile unsigned short *)0x00B00400)
|
||||||
|
#define PATA_DATA_8 ((volatile unsigned char *)0x00B00400)
|
||||||
|
#define PATA_ERROR ((volatile unsigned char *)0x00B00402)
|
||||||
|
#define PATA_SECT_CNT ((volatile unsigned char *)0x00B00404)
|
||||||
|
#define PATA_SECT_SRT ((volatile unsigned char *)0x00B00406)
|
||||||
|
#define PATA_CLDR_LO ((volatile unsigned char *)0x00B00408)
|
||||||
|
#define PATA_CLDR_HI ((volatile unsigned char *)0x00B0040A)
|
||||||
|
#define PATA_HEAD ((volatile unsigned char *)0x00B0040C)
|
||||||
|
#define PATA_CMD_STAT ((volatile unsigned char *)0x00B0040E)
|
||||||
|
|
||||||
|
#endif
|
14
src/include/A2560U/ps2_a2560u.h
Normal file
14
src/include/A2560U/ps2_a2560u.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef __PS2_A2560U_H
|
||||||
|
#define __PS2_A2560U_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ports for the PS/2 keyboard and mouse on the A2560U and A2560U+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PS2_STATUS ((unsigned char *)0x00B02804)
|
||||||
|
#define PS2_CMD_BUF ((unsigned char *)0x00B02804)
|
||||||
|
#define PS2_OUT_BUF ((unsigned char *)0x00B02800)
|
||||||
|
#define PS2_INPT_BUF ((unsigned char *)0x00B02800)
|
||||||
|
#define PS2_DATA_BUF ((unsigned char *)0x00B02800)
|
||||||
|
|
||||||
|
#endif
|
35
src/include/A2560U/sdc_a2560u.h
Normal file
35
src/include/A2560U/sdc_a2560u.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Definitions for access to the SDC controller for the A2560U and A2560U+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SDC_A2560U_H
|
||||||
|
#define __SDC_A2560U_H
|
||||||
|
|
||||||
|
#define GABE_SDC_REG ((volatile unsigned short *)0x00B0051A)
|
||||||
|
#define GABE_SDC_PRESENT 0x0010 /* Is an SD card present? --- 0:Yes, 1:No */
|
||||||
|
#define GABE_SDC_WPROT 0x0020 /* Is the SD card write protected? --- 0:Yes, 1:No */
|
||||||
|
|
||||||
|
#define SDC_VERSION_REG ((unsigned char *)0x00B00300)
|
||||||
|
#define SDC_CONTROL_REG ((unsigned char *)0x00B00301)
|
||||||
|
#define SDC_TRANS_TYPE_REG ((unsigned char *)0x00B00302)
|
||||||
|
|
||||||
|
#define SDC_TRANS_CONTROL_REG ((unsigned char *)0x00B00303)
|
||||||
|
#define SDC_TRANS_STATUS_REG ((unsigned char *)0x00B00304)
|
||||||
|
#define SDC_TRANS_ERROR_REG ((unsigned char *)0x00B00305)
|
||||||
|
#define SDC_DIRECT_ACCESS_REG ((unsigned char *)0x00B00306)
|
||||||
|
#define SDC_SD_ADDR_7_0_REG ((unsigned char *)0x00B00307)
|
||||||
|
#define SDC_SD_ADDR_15_8_REG ((unsigned char *)0x00B00308)
|
||||||
|
#define SDC_SD_ADDR_23_16_REG ((unsigned char *)0x00B00309)
|
||||||
|
#define SDC_SD_ADDR_31_24_REG ((unsigned char *)0x00B0030A)
|
||||||
|
|
||||||
|
#define SDC_SPI_CLK_DEL_REG ((unsigned char *)0x00B0030B)
|
||||||
|
|
||||||
|
#define SDC_RX_FIFO_DATA_REG ((unsigned char *)0x00B00310)
|
||||||
|
#define SDC_RX_FIFO_DATA_CNT_HI ((unsigned char *)0x00B00312)
|
||||||
|
#define SDC_RX_FIFO_DATA_CNT_LO ((unsigned char *)0x00B00313)
|
||||||
|
#define SDC_RX_FIFO_CTRL_REG ((unsigned char *)0x00B00314)
|
||||||
|
|
||||||
|
#define SDC_TX_FIFO_DATA_REG ((unsigned char *)0x00B00320)
|
||||||
|
#define SDC_TX_FIFO_CTRL_REG ((unsigned char *)0x00B00324)
|
||||||
|
|
||||||
|
#endif
|
132
src/include/A2560U/sound_a2560u.h
Normal file
132
src/include/A2560U/sound_a2560u.h
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* Sound device register definitions for the A2560U and A2560U+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SOUND_A2560U_H
|
||||||
|
#define __SOUND_A2560U_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define PSG_PORT ((volatile uint8_t *)0x00B20130) /* Control register for the SN76489 */
|
||||||
|
#define OPL3_PORT ((volatile uint8_t *)0x00B20200) /* Access port for the OPL3 */
|
||||||
|
#define CODEC ((volatile uint16_t *)0x00B20E00) /* Control register for the CODEC */
|
||||||
|
#define SID_INT_L ((volatile uint8_t *)0x00B21000) /* Left SID base */
|
||||||
|
#define SID_INT_R ((volatile uint8_t *)0x00B21200) /* Right SID base */
|
||||||
|
#define SID_INT_N ((volatile uint8_t *)0x00B21400) /* Both SIDs */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A2560U supports two SIDs emulated in the FPGA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal SID Left Channel
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SID_INT_L_V1_FREQ_LO ((uint8_t *)SID_INT_L)
|
||||||
|
#define SID_INT_L_V1_FREQ_HI ((uint8_t *)SID_INT_L+1)
|
||||||
|
#define SID_INT_L_V1_PW_LO ((uint8_t *)SID_INT_L+2)
|
||||||
|
#define SID_INT_L_V1_PW_HI ((uint8_t *)SID_INT_L+3)
|
||||||
|
#define SID_INT_L_V1_CTRL ((uint8_t *)SID_INT_L+4)
|
||||||
|
#define SID_INT_L_V1_ATCK_DECY ((uint8_t *)SID_INT_L+5)
|
||||||
|
#define SID_INT_L_V1_SSTN_RLSE ((uint8_t *)SID_INT_L+6)
|
||||||
|
#define SID_INT_L_V2_FREQ_LO ((uint8_t *)SID_INT_L+7)
|
||||||
|
#define SID_INT_L_V2_FREQ_HI ((uint8_t *)SID_INT_L+8)
|
||||||
|
#define SID_INT_L_V2_PW_LO ((uint8_t *)SID_INT_L+9)
|
||||||
|
#define SID_INT_L_V2_PW_HI ((uint8_t *)SID_INT_L+10)
|
||||||
|
#define SID_INT_L_V2_CTRL ((uint8_t *)SID_INT_L+11)
|
||||||
|
#define SID_INT_L_V2_ATCK_DECY ((uint8_t *)SID_INT_L+12)
|
||||||
|
#define SID_INT_L_V2_SSTN_RLSE ((uint8_t *)SID_INT_L+13)
|
||||||
|
#define SID_INT_L_V3_FREQ_LO ((uint8_t *)SID_INT_L+14)
|
||||||
|
#define SID_INT_L_V3_FREQ_HI ((uint8_t *)SID_INT_L+15)
|
||||||
|
#define SID_INT_L_V3_PW_LO ((uint8_t *)SID_INT_L+16)
|
||||||
|
#define SID_INT_L_V3_PW_HI ((uint8_t *)SID_INT_L+17)
|
||||||
|
#define SID_INT_L_V3_CTRL ((uint8_t *)SID_INT_L+18)
|
||||||
|
#define SID_INT_L_V3_ATCK_DECY ((uint8_t *)SID_INT_L+19)
|
||||||
|
#define SID_INT_L_V3_SSTN_RLSE ((uint8_t *)SID_INT_L+20)
|
||||||
|
#define SID_INT_L_FC_LO ((uint8_t *)SID_INT_L+21)
|
||||||
|
#define SID_INT_L_FC_HI ((uint8_t *)SID_INT_L+22)
|
||||||
|
#define SID_INT_L_RES_FILT ((uint8_t *)SID_INT_L+23)
|
||||||
|
#define SID_INT_L_MODE_VOL ((uint8_t *)SID_INT_L+24)
|
||||||
|
#define SID_INT_L_POT_X ((uint8_t *)SID_INT_L+25)
|
||||||
|
#define SID_INT_L_POT_Y ((uint8_t *)SID_INT_L+26)
|
||||||
|
#define SID_INT_L_OSC3_RND ((uint8_t *)SID_INT_L+27)
|
||||||
|
#define SID_INT_L_ENV3 ((uint8_t *)SID_INT_L+28)
|
||||||
|
#define SID_INT_L_NOT_USED0 ((uint8_t *)SID_INT_L+29)
|
||||||
|
#define SID_INT_L_NOT_USED1 ((uint8_t *)SID_INT_L+30)
|
||||||
|
#define SID_INT_L_NOT_USED2 ((uint8_t *)SID_INT_L+31)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal SID Right Channel
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SID_INT_R_V1_FREQ_LO ((uint8_t *)SID_INT_R)
|
||||||
|
#define SID_INT_R_V1_FREQ_HI ((uint8_t *)SID_INT_R+1)
|
||||||
|
#define SID_INT_R_V1_PW_LO ((uint8_t *)SID_INT_R+2)
|
||||||
|
#define SID_INT_R_V1_PW_HI ((uint8_t *)SID_INT_R+3)
|
||||||
|
#define SID_INT_R_V1_CTRL ((uint8_t *)SID_INT_R+4)
|
||||||
|
#define SID_INT_R_V1_ATCK_DECY ((uint8_t *)SID_INT_R+5)
|
||||||
|
#define SID_INT_R_V1_SSTN_RLSE ((uint8_t *)SID_INT_R+6)
|
||||||
|
#define SID_INT_R_V2_FREQ_LO ((uint8_t *)SID_INT_R+7)
|
||||||
|
#define SID_INT_R_V2_FREQ_HI ((uint8_t *)SID_INT_R+8)
|
||||||
|
#define SID_INT_R_V2_PW_LO ((uint8_t *)SID_INT_R+9)
|
||||||
|
#define SID_INT_R_V2_PW_HI ((uint8_t *)SID_INT_R+10)
|
||||||
|
#define SID_INT_R_V2_CTRL ((uint8_t *)SID_INT_R+11)
|
||||||
|
#define SID_INT_R_V2_ATCK_DECY ((uint8_t *)SID_INT_R+12)
|
||||||
|
#define SID_INT_R_V2_SSTN_RLSE ((uint8_t *)SID_INT_R+13)
|
||||||
|
#define SID_INT_R_V3_FREQ_LO ((uint8_t *)SID_INT_R+14)
|
||||||
|
#define SID_INT_R_V3_FREQ_HI ((uint8_t *)SID_INT_R+15)
|
||||||
|
#define SID_INT_R_V3_PW_LO ((uint8_t *)SID_INT_R+16)
|
||||||
|
#define SID_INT_R_V3_PW_HI ((uint8_t *)SID_INT_R+17)
|
||||||
|
#define SID_INT_R_V3_CTRL ((uint8_t *)SID_INT_R+18)
|
||||||
|
#define SID_INT_R_V3_ATCK_DECY ((uint8_t *)SID_INT_R+19)
|
||||||
|
#define SID_INT_R_V3_SSTN_RLSE ((uint8_t *)SID_INT_R+20)
|
||||||
|
#define SID_INT_R_FC_LO ((uint8_t *)SID_INT_R+21)
|
||||||
|
#define SID_INT_R_FC_HI ((uint8_t *)SID_INT_R+22)
|
||||||
|
#define SID_INT_R_RES_FILT ((uint8_t *)SID_INT_R+23)
|
||||||
|
#define SID_INT_R_MODE_VOL ((uint8_t *)SID_INT_R+24)
|
||||||
|
#define SID_INT_R_POT_X ((uint8_t *)SID_INT_R+25)
|
||||||
|
#define SID_INT_R_POT_Y ((uint8_t *)SID_INT_R+26)
|
||||||
|
#define SID_INT_R_OSC3_RND ((uint8_t *)SID_INT_R+27)
|
||||||
|
#define SID_INT_R_ENV3 ((uint8_t *)SID_INT_R+28)
|
||||||
|
#define SID_INT_R_NOT_USED0 ((uint8_t *)SID_INT_R+29)
|
||||||
|
#define SID_INT_R_NOT_USED1 ((uint8_t *)SID_INT_R+30)
|
||||||
|
#define SID_INT_R_NOT_USED2 ((uint8_t *)SID_INT_R+31)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal SID Neutral Channel - When writting here, the value is written in R and L Channel at the same time
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SID_INT_N_V1_FREQ_LO ((uint8_t *)SID_INT_N)
|
||||||
|
#define SID_INT_N_V1_FREQ_HI ((uint8_t *)SID_INT_N+1)
|
||||||
|
#define SID_INT_N_V1_PW_LO ((uint8_t *)SID_INT_N+2)
|
||||||
|
#define SID_INT_N_V1_PW_HI ((uint8_t *)SID_INT_N+3)
|
||||||
|
#define SID_INT_N_V1_CTRL ((uint8_t *)SID_INT_N+4)
|
||||||
|
#define SID_INT_N_V1_ATCK_DECY ((uint8_t *)SID_INT_N+5)
|
||||||
|
#define SID_INT_N_V1_SSTN_RLSE ((uint8_t *)SID_INT_N+6)
|
||||||
|
#define SID_INT_N_V2_FREQ_LO ((uint8_t *)SID_INT_N+7)
|
||||||
|
#define SID_INT_N_V2_FREQ_HI ((uint8_t *)SID_INT_N+8)
|
||||||
|
#define SID_INT_N_V2_PW_LO ((uint8_t *)SID_INT_N+9)
|
||||||
|
#define SID_INT_N_V2_PW_HI ((uint8_t *)SID_INT_N+10)
|
||||||
|
#define SID_INT_N_V2_CTRL ((uint8_t *)SID_INT_N+11)
|
||||||
|
#define SID_INT_N_V2_ATCK_DECY ((uint8_t *)SID_INT_N+12)
|
||||||
|
#define SID_INT_N_V2_SSTN_RLSE ((uint8_t *)SID_INT_N+13)
|
||||||
|
#define SID_INT_N_V3_FREQ_LO ((uint8_t *)SID_INT_N+14)
|
||||||
|
#define SID_INT_N_V3_FREQ_HI ((uint8_t *)SID_INT_N+15)
|
||||||
|
#define SID_INT_N_V3_PW_LO ((uint8_t *)SID_INT_N+16)
|
||||||
|
#define SID_INT_N_V3_PW_HI ((uint8_t *)SID_INT_N+17)
|
||||||
|
#define SID_INT_N_V3_CTRL ((uint8_t *)SID_INT_N+18)
|
||||||
|
#define SID_INT_N_V3_ATCK_DECY ((uint8_t *)SID_INT_N+19)
|
||||||
|
#define SID_INT_N_V3_SSTN_RLSE ((uint8_t *)SID_INT_N+20)
|
||||||
|
#define SID_INT_N_FC_LO ((uint8_t *)SID_INT_N+21)
|
||||||
|
#define SID_INT_N_FC_HI ((uint8_t *)SID_INT_N+22)
|
||||||
|
#define SID_INT_N_RES_FILT ((uint8_t *)SID_INT_N+23)
|
||||||
|
#define SID_INT_N_MODE_VOL ((uint8_t *)SID_INT_N+24)
|
||||||
|
#define SID_INT_N_POT_X ((uint8_t *)SID_INT_N+25)
|
||||||
|
#define SID_INT_N_POT_Y ((uint8_t *)SID_INT_N+26)
|
||||||
|
#define SID_INT_N_OSC3_RND ((uint8_t *)SID_INT_N+27)
|
||||||
|
#define SID_INT_N_ENV3 ((uint8_t *)SID_INT_N+28)
|
||||||
|
#define SID_INT_N_NOT_USED0 ((uint8_t *)SID_INT_N+29)
|
||||||
|
#define SID_INT_N_NOT_USED1 ((uint8_t *)SID_INT_N+30)
|
||||||
|
#define SID_INT_N_NOT_USED2 ((uint8_t *)SID_INT_N+31)
|
||||||
|
|
||||||
|
#endif
|
54
src/include/A2560U/timers_a2560u.h
Normal file
54
src/include/A2560U/timers_a2560u.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
* @file timers_a2560u.h
|
||||||
|
*
|
||||||
|
* Define timer registers on the A2560U and U+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __A2560U_TIMERS_H
|
||||||
|
#define __A2560U_TIMERS_H
|
||||||
|
|
||||||
|
/** Timer control register 0: timers 0, 1, and 2 */
|
||||||
|
#define TIMER_TCR0 ((unsigned long *)0x00B00200)
|
||||||
|
#define TCR_ENABLE_0 0x00000001 /** Enable counter 0 */
|
||||||
|
#define TCR_CLEAR_0 0x00000002 /** Master clear of counter 0 */
|
||||||
|
#define TCR_LOAD_0 0x00000004 /** Master load of counter 0 */
|
||||||
|
#define TCR_CNTUP_0 0x00000008 /** Counter 0 Count up if 1, count down if 0 */
|
||||||
|
#define TCR_INE_0 0x00000080 /** Interrupt enable for counter 0 */
|
||||||
|
|
||||||
|
#define TCR_ENABLE_1 0x00000100 /** Enable counter 1 */
|
||||||
|
#define TCR_CLEAR_1 0x00000200 /** Master clear of counter 1 */
|
||||||
|
#define TCR_LOAD_1 0x00000400 /** Master load of counter 1 */
|
||||||
|
#define TCR_CNTUP_1 0x00000800 /** Counter 1 Count up if 1, count down if 0 */
|
||||||
|
#define TCR_INE_1 0x00008000 /** Interrupt enable for counter 1 */
|
||||||
|
|
||||||
|
#define TCR_ENABLE_2 0x00010000 /** Enable counter 2 */
|
||||||
|
#define TCR_CLEAR_2 0x00020000 /** Master clear of counter 2 */
|
||||||
|
#define TCR_LOAD_2 0x00040000 /** Master load of counter 2 */
|
||||||
|
#define TCR_CNTUP_2 0x00080000 /** Counter 2 Count up if 1, count down if 0 */
|
||||||
|
#define TCR_INE_2 0x00800000 /** Interrupt enable for counter 2 */
|
||||||
|
|
||||||
|
/** Timer control register 1: timer 3 */
|
||||||
|
#define TIMER_TCR1 ((unsigned long *)0x00B00204)
|
||||||
|
#define TCR_ENABLE_3 0x00000001 /** Enable counter 3 */
|
||||||
|
#define TCR_CLEAR_3 0x00000002 /** Master clear of counter 3 */
|
||||||
|
#define TCR_LOAD_3 0x00000004 /** Master load of counter 3 */
|
||||||
|
#define TCR_CNTUP_3 0x00000008 /** Counter 3 Count up if 1, count down if 0 */
|
||||||
|
#define TCR_RECLR_3 0x00000010 /** Enable reclear of timer 3 */
|
||||||
|
#define TCR_RELOAD_3 0x00000020 /** Enable reload of timer 3 */
|
||||||
|
#define TCR_INE_3 0x00000080 /** Interrupt enable for counter 3 */
|
||||||
|
|
||||||
|
#define TCR_STAT_EQ0 0x08000000 /** Read only: timer 0 is equal to its comparison value */
|
||||||
|
#define TCR_STAT_EQ1 0x10000000 /** Read only: timer 1 is equal to its comparison value */
|
||||||
|
#define TCR_STAT_EQ2 0x20000000 /** Read only: timer 2 is equal to its comparison value */
|
||||||
|
#define TCR_STAT_EQ3 0x40000000 /** Read only: timer 3 is equal to its comparison value */
|
||||||
|
|
||||||
|
#define TIMER_VALUE_0 ((unsigned long *)0x00B00208)
|
||||||
|
#define TIMER_COMPARE_0 ((unsigned long *)0x00B0020C)
|
||||||
|
#define TIMER_VALUE_1 ((unsigned long *)0x00B00210)
|
||||||
|
#define TIMER_COMPARE_1 ((unsigned long *)0x00B00214)
|
||||||
|
#define TIMER_VALUE_2 ((unsigned long *)0x00B00218)
|
||||||
|
#define TIMER_COMPARE_2 ((unsigned long *)0x00B0021C)
|
||||||
|
#define TIMER_VALUE_3 ((unsigned long *)0x00B00220)
|
||||||
|
#define TIMER_COMPARE_3 ((unsigned long *)0x00B00224)
|
||||||
|
|
||||||
|
#endif
|
59
src/include/A2560X/gabe_a2560x.h
Normal file
59
src/include/A2560X/gabe_a2560x.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/**
|
||||||
|
* @file gabe_a2560k.h
|
||||||
|
*
|
||||||
|
* Define miscellaneous GABE registers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GABE_A2560K_H
|
||||||
|
#define __GABE_A2560K_H
|
||||||
|
|
||||||
|
// These are 32bits Wide Registers since they are internal to the VICKY III
|
||||||
|
#define GABE_CTRL_REG ((volatile unsigned int *)0xFEC00000)
|
||||||
|
#define POWER_ON_LED 0x00000001
|
||||||
|
#define SDCARD_LED 0x00000002
|
||||||
|
#define BUZZER_CONTROL 0x00000010
|
||||||
|
#define MANUAL_RESET 0x00008000 // Make sure the word "DEAD" is written in GABE_RESET_ID
|
||||||
|
|
||||||
|
#define GABE_LFSR_REG0 ((volatile unsigned int *)0xFEC00004)
|
||||||
|
|
||||||
|
#define RGB_LED ((volatile unsigned int *)0xFEC00008) // Writing Only - A2560K Only - 0x__RRGGBB
|
||||||
|
#define GABE_LFSR_STATDATA ((volatile unsigned int *)0xFEC00008) // Read Only
|
||||||
|
|
||||||
|
#define GABE_SUBVER_ID ((volatile unsigned int *)0xFEC0000C) // Subversion[31:16], Machine ID[3:2] - Read Only
|
||||||
|
#define GABE_CPU_ID_MASK 0x0000FF00
|
||||||
|
#define GABE_CPU_SPD_MASK 0x000000E0
|
||||||
|
#define GABE_ID_MASK 0x0000000C
|
||||||
|
#define GABE_CHIP_SV_MASK 0xFFFF0000
|
||||||
|
|
||||||
|
#define GABE_CHIP_VERSION ((volatile unsigned int *)0xFEC00010) // Number[31:16], Version[15:0]
|
||||||
|
#define GABE_CHIP_V_MASK 0x0000FFFF
|
||||||
|
#define GABE_CHIP_N_MASK 0xFFFF0000
|
||||||
|
|
||||||
|
|
||||||
|
#define GABE_FIRMWARE_DATE ((volatile unsigned int *)0xFEC00014) // xxDDMMYY
|
||||||
|
#define GABE_FIRMWARE_DATE_YEAR_MASK 0x000000FF
|
||||||
|
#define GABE_FIRMWARE_DATE_MONTH_MASK 0x0000FF00
|
||||||
|
#define GABE_FIRMWARE_DATE_DAY_MASK 0x00FF0000
|
||||||
|
|
||||||
|
// Those registers in the GenX/A2560X are 16bits Wide.
|
||||||
|
#define GABE_DIP_REG ((volatile unsigned short *)0xFEC00518)
|
||||||
|
#define GABE_DIP_BOOT_MASK 0x0003 /* Mask for the boot mode: */
|
||||||
|
#define GABE_DIP_USER_MASK 0x0300 /* Mask for the user switches: */
|
||||||
|
|
||||||
|
// This applies to GenX and A2560X ONLY
|
||||||
|
#define GABE_SUB_MODEL_ID ((volatile unsigned short *)0xFEC00514)
|
||||||
|
#define GABE_SUB_MOD_MASK 0x0003 /* Mask for the sub-model: PB, LB, CU*/
|
||||||
|
|
||||||
|
#define GABE_GENX_STAT_LEDS ((volatile unsigned long *)0xFEC0000C)
|
||||||
|
#define GABE_GENX_STAT_LED_0_B 0x00000001 /* LED 0 (Close to DEL key) -- Blue ON */
|
||||||
|
#define GABE_GENX_STAT_LED_0_G 0x00000002 /* LED 0 (Close to DEL key) -- Green ON */
|
||||||
|
#define GABE_GENX_STAT_LED_0_R 0x00000004 /* LED 0 (Close to DEL key) -- Red ON */
|
||||||
|
#define GABE_GENX_STAT_LED_1_B 0x00000008 /* LED 1 (Below #0) -- Blue ON */
|
||||||
|
#define GABE_GENX_STAT_LED_1_G 0x00000010 /* LED 1 (Below #0) -- Green ON */
|
||||||
|
#define GABE_GENX_STAT_LED_1_R 0x00000020 /* LED 1 (Below #0) -- Red ON */
|
||||||
|
#define GABE_GENX_STAT_LED_2_B 0x00000040 /* LED 2 (above arrow) -- Blue ON */
|
||||||
|
#define GABE_GENX_STAT_LED_2_G 0x00000080 /* LED 2 (above arrow) -- Green ON */
|
||||||
|
#define GABE_GENX_STAT_LED_2_R 0x00000100 /* LED 2 (above arrow) -- Red ON */
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
35
src/include/A2560X/sdc_a2560x.h
Normal file
35
src/include/A2560X/sdc_a2560x.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Definitions for access to the SDC controller
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SDC_A2560X_H
|
||||||
|
#define __SDC_A2560X_H
|
||||||
|
|
||||||
|
#define GABE_SDC_REG ((volatile unsigned short *)0xFEC0051A)
|
||||||
|
#define GABE_SDC_PRESENT 0x0100 /* Is an SD card present? --- 0:Yes, 1:No */
|
||||||
|
#define GABE_SDC_WPROT 0x0200 /* Is the SD card write protected? --- 0:Yes, 1:No */
|
||||||
|
|
||||||
|
#define SDC_VERSION_REG ((unsigned char *)0xFEC00300)
|
||||||
|
#define SDC_CONTROL_REG ((unsigned char *)0xFEC00301)
|
||||||
|
#define SDC_TRANS_TYPE_REG ((unsigned char *)0xFEC00302)
|
||||||
|
|
||||||
|
#define SDC_TRANS_CONTROL_REG ((unsigned char *)0xFEC00303)
|
||||||
|
#define SDC_TRANS_STATUS_REG ((unsigned char *)0xFEC00304)
|
||||||
|
#define SDC_TRANS_ERROR_REG ((unsigned char *)0xFEC00305)
|
||||||
|
#define SDC_DIRECT_ACCESS_REG ((unsigned char *)0xFEC00306)
|
||||||
|
#define SDC_SD_ADDR_7_0_REG ((unsigned char *)0xFEC00307)
|
||||||
|
#define SDC_SD_ADDR_15_8_REG ((unsigned char *)0xFEC00308)
|
||||||
|
#define SDC_SD_ADDR_23_16_REG ((unsigned char *)0xFEC00309)
|
||||||
|
#define SDC_SD_ADDR_31_24_REG ((unsigned char *)0xFEC0030A)
|
||||||
|
|
||||||
|
#define SDC_SPI_CLK_DEL_REG ((unsigned char *)0xFEC0030B)
|
||||||
|
|
||||||
|
#define SDC_RX_FIFO_DATA_REG ((unsigned char *)0xFEC00310)
|
||||||
|
#define SDC_RX_FIFO_DATA_CNT_HI ((unsigned char *)0xFEC00312)
|
||||||
|
#define SDC_RX_FIFO_DATA_CNT_LO ((unsigned char *)0xFEC00313)
|
||||||
|
#define SDC_RX_FIFO_CTRL_REG ((unsigned char *)0xFEC00314)
|
||||||
|
|
||||||
|
#define SDC_TX_FIFO_DATA_REG ((unsigned char *)0xFEC00320)
|
||||||
|
#define SDC_TX_FIFO_CTRL_REG ((unsigned char *)0xFEC00324)
|
||||||
|
|
||||||
|
#endif
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue