First commit
This commit is contained in:
commit
2d7bfa6436
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
.build/
|
||||
.clangd
|
||||
compile_commands.json
|
5
build.sh
Executable file
5
build.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
rm -rf .build
|
||||
mkdir .build
|
||||
# zasm src/crt0.z80 -y -o .build/xed.com -L ../sdcc/device/lib
|
||||
zasm src/crt0.z80 -y -o .build/xed.com -L lib -I ../sdcc-code/sdcc/device/include
|
20
include/console.h
Normal file
20
include/console.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef CONSOLE_H
|
||||
#define CONSOLE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SCREEN_WIDTH 80
|
||||
#define SCREEN_HEIGHT 45
|
||||
|
||||
extern uint8_t console_getchar();
|
||||
extern void console_putchar(uint8_t c);
|
||||
extern void console_printstring(const uint8_t* c);
|
||||
|
||||
extern void console_revon();
|
||||
extern void console_revoff();
|
||||
|
||||
extern void console_clear();
|
||||
extern void console_clear_eol();
|
||||
extern void console_goto(uint8_t x, uint8_t y);
|
||||
|
||||
#endif
|
36
lib/___itoa.s
Normal file
36
lib/___itoa.s
Normal file
|
@ -0,0 +1,36 @@
|
|||
#code _CODE
|
||||
|
||||
#include "___uitoa.s"
|
||||
|
||||
;
|
||||
;void __itoa(int value, char *string, unsigned char radix);
|
||||
;
|
||||
___itoa::
|
||||
push ix
|
||||
ld ix, #0
|
||||
add ix, sp
|
||||
;
|
||||
; 4(ix) - value
|
||||
; 6(ix) - string
|
||||
; 8(ix) - radix
|
||||
;
|
||||
ld e, 4 (ix)
|
||||
ld d, 5 (ix)
|
||||
bit 7, d
|
||||
jp Z, ___uitoa_de
|
||||
;positive/negative numbers are supported only for radix=10
|
||||
ld a, 8 (ix)
|
||||
cp a, #10
|
||||
jp NZ, ___uitoa_de
|
||||
;add minus sign to result and inverse value
|
||||
ld hl, #0
|
||||
or a, a
|
||||
sbc hl, de
|
||||
ex de, hl
|
||||
ld l, 6 (ix)
|
||||
ld h, 7 (ix)
|
||||
ld (hl), #0x2D ;minus symbol
|
||||
inc hl
|
||||
ld 6 (ix), l
|
||||
ld 7 (ix), h
|
||||
jp ___uitoa_dehl
|
37
lib/___sdcc_call_hl.s
Normal file
37
lib/___sdcc_call_hl.s
Normal file
|
@ -0,0 +1,37 @@
|
|||
;--------------------------------------------------------------------------
|
||||
; crtcall.s
|
||||
;
|
||||
; Copyright (C) 2011, Maarten Brock
|
||||
;
|
||||
; This library is free software; you can redistribute it and/or modify it
|
||||
; under the terms of the GNU General Public License as published by the
|
||||
; Free Software Foundation; either version 2, or (at your option) any
|
||||
; later version.
|
||||
;
|
||||
; This library is distributed in the hope that it will be useful,
|
||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
; GNU General Public License for more details.
|
||||
;
|
||||
; You should have received a copy of the GNU General Public License
|
||||
; along with this library; see the file COPYING. If not, write to the
|
||||
; Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
|
||||
; MA 02110-1301, USA.
|
||||
;
|
||||
; As a special exception, if you link this library with other files,
|
||||
; some of which are compiled with SDCC, to produce an executable,
|
||||
; this library does not by itself cause the resulting executable to
|
||||
; be covered by the GNU General Public License. This exception does
|
||||
; not however invalidate any other reasons why the executable file
|
||||
; might be covered by the GNU General Public License.
|
||||
;--------------------------------------------------------------------------
|
||||
|
||||
.area _CODE
|
||||
|
||||
.globl ___sdcc_call_hl
|
||||
|
||||
; The Z80 has the jp (hl) instruction, which is perfect for implementing function pointers.
|
||||
|
||||
___sdcc_call_hl:
|
||||
jp (hl)
|
||||
|
30
lib/___strreverse.s
Normal file
30
lib/___strreverse.s
Normal file
|
@ -0,0 +1,30 @@
|
|||
#code _CODE
|
||||
;
|
||||
;void __reverse(char *beg, char *end);
|
||||
;
|
||||
___strreverse::
|
||||
pop bc
|
||||
pop de
|
||||
pop hl
|
||||
push hl
|
||||
push de
|
||||
push bc
|
||||
;
|
||||
;in: HL - pointer to end of string (null symbol), DE - pointer to start of string
|
||||
;
|
||||
___strreverse_reg::
|
||||
jr 110$
|
||||
100$:
|
||||
add hl, de
|
||||
ld a, (de)
|
||||
ld c, (hl)
|
||||
ld (hl), a
|
||||
ld a, c
|
||||
ld (de), a
|
||||
inc de
|
||||
110$:
|
||||
dec hl
|
||||
or a, a
|
||||
sbc hl, de
|
||||
jr NC, 100$
|
||||
ret
|
172
lib/___uitoa.s
Normal file
172
lib/___uitoa.s
Normal file
|
@ -0,0 +1,172 @@
|
|||
#code _CODE
|
||||
|
||||
#include "___uitobcd.s"
|
||||
#include "___strreverse.s"
|
||||
|
||||
;
|
||||
;void __uitoa(unsigned int value, char *string, unsigned char radix);
|
||||
;
|
||||
___uitoa::
|
||||
push ix
|
||||
ld ix, #0
|
||||
add ix, sp
|
||||
;
|
||||
; 4(ix) - value
|
||||
; 6(ix) - string
|
||||
; 8(ix) - radix
|
||||
;
|
||||
ld e, 4 (ix)
|
||||
ld d, 5 (ix)
|
||||
;
|
||||
___uitoa_de:
|
||||
ld l, 6 (ix)
|
||||
ld h, 7 (ix)
|
||||
;
|
||||
___uitoa_dehl:
|
||||
ld a, e
|
||||
or a, d
|
||||
jr NZ, 100$
|
||||
;
|
||||
ld (hl), #0x30
|
||||
inc hl
|
||||
jp 190$
|
||||
100$:
|
||||
ld a, 8 (ix)
|
||||
cp a, #10 ;most popular radix
|
||||
jr NZ, 110$
|
||||
;
|
||||
;-------- decimal convertion
|
||||
; this algorithm up to 2 times faster than generic
|
||||
;
|
||||
ld c, l
|
||||
ld b, h
|
||||
ld hl, #-4
|
||||
add hl, sp
|
||||
ld sp, hl
|
||||
push bc
|
||||
push hl
|
||||
push de
|
||||
call ___uitobcd
|
||||
ld hl, #4
|
||||
add hl, sp
|
||||
ld sp, hl
|
||||
pop de ;DE - pointer to string
|
||||
inc hl
|
||||
inc hl ;HL - pointer to BCD value
|
||||
ld b, #3 ;number of bytes in BCD value
|
||||
ld a, #0x30 ;ASCII code of '0'
|
||||
103$:
|
||||
rrd
|
||||
ld (de), a
|
||||
inc de
|
||||
rrd
|
||||
ld (de), a
|
||||
inc de
|
||||
inc hl
|
||||
djnz 103$
|
||||
;
|
||||
; pop af
|
||||
; pop af
|
||||
;skip trailing zeroes
|
||||
ld b, #5 ;real BCD number is at most 5 digits
|
||||
dec de ;so always skip last zero
|
||||
105$:
|
||||
dec de
|
||||
ld a, (de)
|
||||
cp a, #0x30
|
||||
jr NZ, 107$ ;break loop if non-zero found
|
||||
djnz 105$
|
||||
107$:
|
||||
inc de ;always point to symbol next to last significant
|
||||
ex de, hl
|
||||
jr 190$
|
||||
;
|
||||
;---------------------------
|
||||
;
|
||||
110$:
|
||||
cp a, #2
|
||||
jr C, 190$ ;radix is less than 2
|
||||
;
|
||||
ld c, a
|
||||
dec c
|
||||
and a, c
|
||||
jr NZ, 150$
|
||||
;
|
||||
;-------- radix is power of 2
|
||||
;
|
||||
; DE - value, HL - pointer to string, C - mask
|
||||
120$:
|
||||
ld a, e
|
||||
ld b, c
|
||||
125$:
|
||||
srl d
|
||||
rr e
|
||||
srl b
|
||||
jr NZ, 125$
|
||||
;
|
||||
and a, c
|
||||
add a, #0x30
|
||||
cp a, #0x3A ;convert to 0...9A...Z
|
||||
jr C, 130$
|
||||
add a, #7
|
||||
130$:
|
||||
ld (hl), a
|
||||
inc hl
|
||||
ld a, e
|
||||
or a, d
|
||||
jr NZ, 120$
|
||||
jr 190$
|
||||
;
|
||||
;---------------------------
|
||||
;
|
||||
;-------- custom radix (generic algorithm)
|
||||
;
|
||||
150$:
|
||||
ex de, hl
|
||||
160$:
|
||||
ld c, 8 (ix)
|
||||
call ___divu16_8
|
||||
add a, #0x30
|
||||
cp a, #0x3A
|
||||
jr C, 165$
|
||||
add a, #7
|
||||
165$:
|
||||
ld (de), a
|
||||
inc de
|
||||
ld a, l
|
||||
or h
|
||||
jr NZ, 160$
|
||||
ex de, hl
|
||||
; jr 190$
|
||||
;
|
||||
;---------------------------
|
||||
;
|
||||
;-------- finish string and reverse order
|
||||
190$:
|
||||
ld (hl), #0
|
||||
ld e, 6 (ix)
|
||||
ld d, 7 (ix)
|
||||
call ___strreverse_reg
|
||||
ld sp, ix
|
||||
pop ix
|
||||
ret
|
||||
;
|
||||
;
|
||||
;in: HL - divident, C - divisor
|
||||
;out: HL - quotient, A - remainder
|
||||
___divu16_8:
|
||||
xor a, a
|
||||
ld b, #16
|
||||
100$:
|
||||
add hl, hl
|
||||
rla
|
||||
jr c, 110$
|
||||
cp a, c
|
||||
jr c, 120$
|
||||
110$:
|
||||
sub a, c
|
||||
inc l
|
||||
120$:
|
||||
djnz 100$
|
||||
ret
|
||||
|
57
lib/___uitobcd.s
Normal file
57
lib/___uitobcd.s
Normal file
|
@ -0,0 +1,57 @@
|
|||
#code _CODE
|
||||
|
||||
; void __uitobcd (unsigned int v, unsigned char bcd[3])
|
||||
; __uitobcd converts v to BCD representation to the bcd.
|
||||
; bcd[] will contain BCD value.
|
||||
;
|
||||
___uitobcd:
|
||||
push ix
|
||||
ld ix, #0
|
||||
add ix, sp
|
||||
;
|
||||
ld bc, #0x1000
|
||||
ld d, c
|
||||
ld e, c
|
||||
ld l, 4 (ix)
|
||||
ld h, 5 (ix)
|
||||
;
|
||||
;--- begin speed optimization
|
||||
;
|
||||
ld a, h
|
||||
or a, a
|
||||
jr NZ, 100$
|
||||
;
|
||||
ld h, l
|
||||
srl b
|
||||
;
|
||||
;--- end speed optimization
|
||||
;
|
||||
; HL - binary value
|
||||
; CDE - future BCD value
|
||||
; B - bits count (16)
|
||||
100$:
|
||||
add hl, hl
|
||||
ld a, e
|
||||
adc a, a
|
||||
daa
|
||||
ld e, a
|
||||
ld a, d
|
||||
adc a, a
|
||||
daa
|
||||
ld d, a
|
||||
ld a, c
|
||||
adc a, a
|
||||
daa
|
||||
ld c, a
|
||||
djnz 100$
|
||||
;
|
||||
ld l, 6 (ix)
|
||||
ld h, 7 (ix)
|
||||
ld (hl), e
|
||||
inc hl
|
||||
ld (hl), d
|
||||
inc hl
|
||||
ld (hl), c
|
||||
;
|
||||
pop ix
|
||||
ret
|
40
src/console.c
Normal file
40
src/console.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include <stdlib.h>
|
||||
#include "console.h"
|
||||
|
||||
void console_printstring(const uint8_t* c) {
|
||||
while (*c != 0x00) {
|
||||
console_putchar(*c);
|
||||
c++;
|
||||
}
|
||||
}
|
||||
|
||||
void console_revon() {
|
||||
console_printstring("\033[7m");
|
||||
}
|
||||
|
||||
void console_revoff() {
|
||||
console_printstring("\033[0m");
|
||||
}
|
||||
|
||||
void console_clear() {
|
||||
console_printstring("\033[2J");
|
||||
}
|
||||
|
||||
void console_clear_eol() {
|
||||
console_printstring("\033[K");
|
||||
}
|
||||
|
||||
void console_goto(uint8_t x, uint8_t y) {
|
||||
if (!x && !y) {
|
||||
console_printstring("\033[H");
|
||||
} else {
|
||||
console_printstring("\033[");
|
||||
static char buffer[10];
|
||||
__itoa(y, buffer, 10);
|
||||
console_printstring(buffer);
|
||||
console_putchar(';');
|
||||
__itoa(x, buffer, 10);
|
||||
console_printstring(buffer);
|
||||
console_putchar('H');
|
||||
}
|
||||
}
|
24
src/console.z80
Normal file
24
src/console.z80
Normal file
|
@ -0,0 +1,24 @@
|
|||
#code _CODE
|
||||
|
||||
bios_call:
|
||||
ld hl, (1)
|
||||
add l
|
||||
ld l, a
|
||||
jp nc, bios_call_cont
|
||||
inc h
|
||||
bios_call_cont:
|
||||
jp (hl)
|
||||
|
||||
_console_getchar::
|
||||
ld a, 6
|
||||
call bios_call
|
||||
ld l, a
|
||||
ret
|
||||
|
||||
_console_putchar::
|
||||
ld iy, 2
|
||||
add iy, sp
|
||||
ld c, (iy)
|
||||
ld a, 9
|
||||
call bios_call
|
||||
ret
|
83
src/crt0.z80
Normal file
83
src/crt0.z80
Normal file
|
@ -0,0 +1,83 @@
|
|||
#target bin
|
||||
|
||||
#code _HOME, 0x100
|
||||
#code _CODE
|
||||
#code _GSINIT
|
||||
#code _GSFINAL
|
||||
#code _INITIALIZER
|
||||
#code _CABS
|
||||
#code _CODE_END
|
||||
|
||||
#data _DATA, _CODE_END
|
||||
#data _INITIALIZED
|
||||
#data _DABS
|
||||
#data _HEAP
|
||||
|
||||
#cflags -I../include
|
||||
#include "xed.c"
|
||||
#include "console.c"
|
||||
#include "console.z80"
|
||||
#include standard library
|
||||
|
||||
#code _HOME
|
||||
init:
|
||||
ld a, 0x77
|
||||
out (0x80), a
|
||||
; Store the old stack location before setting new
|
||||
ld (oldstack), sp
|
||||
ld sp, #stack_end
|
||||
|
||||
; Initialise global variables
|
||||
call gsinit
|
||||
|
||||
; Execute program
|
||||
call _main
|
||||
|
||||
; Run the exit code
|
||||
jp _exit
|
||||
|
||||
|
||||
#code _CODE
|
||||
; Get char through bdos
|
||||
_putchar::
|
||||
ld iy, 2
|
||||
add iy, sp
|
||||
ld e, (iy)
|
||||
ld c, 2
|
||||
call 5
|
||||
ld l, e
|
||||
ret
|
||||
|
||||
; Put char through bdos
|
||||
_getchar::
|
||||
ld c, 1
|
||||
call 5
|
||||
ret
|
||||
|
||||
; Set the old stack back and return
|
||||
; This needs to be adjusted if the program overwrites the ccp
|
||||
_exit::
|
||||
ld sp, (oldstack)
|
||||
ret
|
||||
|
||||
#code _GSINIT
|
||||
; Initialze data
|
||||
gsinit::
|
||||
ld bc, _INITIALIZER_size
|
||||
ld a, b
|
||||
or a, c
|
||||
jr z, gsinit_next
|
||||
ld de, _INITIALIZED
|
||||
ld hl, _INITIALIZER
|
||||
ldir
|
||||
|
||||
gsinit_next:
|
||||
#code _GSFINAL
|
||||
ret
|
||||
|
||||
#data _DATA
|
||||
oldstack:
|
||||
.ds 2
|
||||
stack:
|
||||
.ds 128
|
||||
stack_end:
|
208
src/xed.c
Normal file
208
src/xed.c
Normal file
|
@ -0,0 +1,208 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "console.h"
|
||||
|
||||
// NOTES:
|
||||
// This is going to be a line based editor
|
||||
// Lines are gonig to be max 80 char so we do nog have to deal with text wrap around
|
||||
//
|
||||
// A line is going to be split around the cursor
|
||||
// If the cursor moves we need to move chars from one side to the other
|
||||
//
|
||||
// As an optimization we only have to redraw the section after the cursor
|
||||
// As this is this is the only text that needs to move as a result of insertions
|
||||
|
||||
void exit();
|
||||
|
||||
uint8_t line_buffer[SCREEN_WIDTH+2] = {0};
|
||||
uint8_t* gap_start = line_buffer;
|
||||
uint8_t* gap_end = line_buffer + SCREEN_WIDTH;
|
||||
|
||||
uint8_t line = 0;
|
||||
uint8_t column = 0;
|
||||
|
||||
uint8_t next() {
|
||||
if (column < 80) {
|
||||
uint8_t* p = gap_end+1;
|
||||
uint8_t temp = *gap_start;
|
||||
|
||||
*gap_start = *p;
|
||||
*p = temp;
|
||||
gap_start++;
|
||||
gap_end++;
|
||||
|
||||
column++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// @todo Add boundary checking
|
||||
uint8_t previous() {
|
||||
if (column > 0) {
|
||||
uint8_t* p = gap_start-1;
|
||||
uint8_t temp = *gap_end;
|
||||
|
||||
*gap_end = *p;
|
||||
*p = temp;
|
||||
gap_start--;
|
||||
gap_end--;
|
||||
|
||||
column--;
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t insert(uint8_t c) {
|
||||
if (column < 80) {
|
||||
*gap_start = c;
|
||||
gap_start++;
|
||||
column++;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t remove() {
|
||||
if (column > 0) {
|
||||
gap_start--;
|
||||
*gap_start = 0;
|
||||
column--;
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef void (*mode_function)(uint8_t);
|
||||
struct Mode {
|
||||
const char* name;
|
||||
uint8_t id;
|
||||
mode_function function;
|
||||
};
|
||||
|
||||
struct Mode* current_mode;
|
||||
|
||||
void normal_function(uint8_t c);
|
||||
void insert_function(uint8_t c);
|
||||
|
||||
struct Mode normal_mode = {"NORMAL", 0, normal_function};
|
||||
struct Mode insert_mode = {"INSERT", 1, insert_function};
|
||||
|
||||
uint8_t last_mode_id = 0xFF;
|
||||
|
||||
void insert_function(uint8_t c) {
|
||||
// We can optimize this by only drawing the gap end part
|
||||
console_goto(column+1, line+1);
|
||||
console_clear_eol();
|
||||
/* console_printstring(line_buffer); */
|
||||
console_printstring(gap_end+1);
|
||||
|
||||
console_goto(column+1, line+1);
|
||||
|
||||
switch (c) {
|
||||
// Backspace removes last char
|
||||
case 8:
|
||||
// @todo Figure out backspace
|
||||
remove();
|
||||
break;
|
||||
|
||||
// Escape moves back to normal mode
|
||||
case 27:
|
||||
current_mode = &normal_mode;
|
||||
return;
|
||||
|
||||
default:
|
||||
if (insert(c)) {
|
||||
console_putchar(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void normal_function(uint8_t c) {
|
||||
switch (c) {
|
||||
case 'l':
|
||||
next();
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
previous();
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
current_mode = &insert_mode;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
next();
|
||||
current_mode = &insert_mode;
|
||||
break;
|
||||
|
||||
case 27:
|
||||
console_clear();
|
||||
console_goto(0, 0);
|
||||
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
console_clear();
|
||||
console_goto(0, 0);
|
||||
|
||||
static char buffer[10];
|
||||
for (int b = 0; b < 16; ++b) {
|
||||
console_printstring("\033[");
|
||||
if (b < 8) {
|
||||
__itoa(b+40, buffer, 10);
|
||||
} else {
|
||||
__itoa(b+100-8, buffer, 10);
|
||||
}
|
||||
console_printstring(buffer);
|
||||
console_putchar('m');
|
||||
|
||||
for (int f = 0; f < 16; ++f) {
|
||||
|
||||
console_printstring("\033[");
|
||||
if (f < 8) {
|
||||
__itoa(f+30, buffer, 10);
|
||||
} else {
|
||||
__itoa(f+90-8, buffer, 10);
|
||||
}
|
||||
console_printstring(buffer);
|
||||
console_putchar('m');
|
||||
|
||||
console_printstring("Test");
|
||||
}
|
||||
|
||||
console_printstring("\n\r");
|
||||
}
|
||||
|
||||
console_printstring("\033[0m");
|
||||
|
||||
return 0;
|
||||
|
||||
console_clear();
|
||||
current_mode = &normal_mode;
|
||||
|
||||
while (1) {
|
||||
if (last_mode_id != current_mode->id) {
|
||||
console_goto(0, SCREEN_HEIGHT);
|
||||
console_clear_eol();
|
||||
console_revon();
|
||||
console_printstring(current_mode->name);
|
||||
console_revoff();
|
||||
last_mode_id = current_mode->id;
|
||||
}
|
||||
|
||||
console_goto(column+1, line+1);
|
||||
|
||||
char c = console_getchar();
|
||||
|
||||
current_mode->function(c);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user