First commit

This commit is contained in:
Dreaded_X 2020-09-19 22:16:34 +02:00
commit 2d7bfa6436
13 changed files with 717 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.build/
.clangd
compile_commands.json

5
build.sh Executable file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);
}
}

2
upload.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/bash
cd ../z80-cpm && ./build.py && sudo dd if=.build/disk.img of=/dev/sdb