From: Alan Cox Date: Tue, 31 Mar 2015 21:54:38 +0000 (+0100) Subject: nc100: first draft graphics and audio support X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=37ee8f190c633a4d152fdb0524253010c7e3b9b0;p=FUZIX.git nc100: first draft graphics and audio support --- diff --git a/Kernel/platform-nc100/Makefile b/Kernel/platform-nc100/Makefile index 148d521e..1b250068 100644 --- a/Kernel/platform-nc100/Makefile +++ b/Kernel/platform-nc100/Makefile @@ -1,5 +1,5 @@ -CSRCS = devlpr.c devtty.c devrd.c +CSRCS = devlpr.c devtty.c devrd.c devaudio.c devgfx.c CSRCS += devices.c main.c ASRCS = nc100.s crt0.s diff --git a/Kernel/platform-nc100/config.h b/Kernel/platform-nc100/config.h index fa0b23a1..9fe41a61 100644 --- a/Kernel/platform-nc100/config.h +++ b/Kernel/platform-nc100/config.h @@ -22,6 +22,8 @@ #define MAX_MAPS 16 /* We want the 4x6 font */ #define CONFIG_FONT_4X6 +/* We have audio (just about) */ +#define CONFIG_AUDIO /* As reported to user space - 4 banks, 16K page size */ #define CONFIG_BANKS 4 @@ -51,11 +53,12 @@ #define CMDLINE NULL /* Location of root dev name */ /* Device parameters */ -#define NUM_DEV_TTY 3 +#define NUM_DEV_TTY 2 #define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ #define NBUFS 10 /* Number of block buffers */ #ifdef CONFIG_NC200 #define NMOUNTS 2 /* Floppy can also be mounted */ #else #define NMOUNTS 1 /* Number of mounts at a time - nothing mountable! */ +#define BOOTDEVICE 0x0100 /* Only one possible option */ #endif diff --git a/Kernel/platform-nc100/devaudio.c b/Kernel/platform-nc100/devaudio.c new file mode 100644 index 00000000..05bfc9f4 --- /dev/null +++ b/Kernel/platform-nc100/devaudio.c @@ -0,0 +1,84 @@ +/* + * Audio support for the NC100. Pretty minimal + */ + +#include +#include + +/* Simple two channel beeper style ton generator with no volume control */ +const struct audio audio_info = { + AUDIO_BEEPER, + 2, + 0 +}; + +static uint8_t audio_count[2]; + +static inline uint16_t devaudio_map(uint16_t hz) +{ + /* The given equation is freq = 1000000/(rate * 2 * 1.6276) */ + /* ie rate = 307201/freq */ + return 307201UL/hz; +} + +/* The sound core will call this when it wants to stop a sound */ +void devaudio_stop(uint8_t channel) +{ + out(0x51 + 2 * channel, 0xFF); + audio_count[channel] = 0; + wakeup(&audio_count[channel]); +} + +/* The NC100 has two tone generators, no volume control, nothing fancy + at all */ +int devaudio_play(void) +{ + uint16_t rate; + audio_count[sound.channel] = sound.time; + rate = devaudio_map(sound.freq); + if (sound.volume > 32) { /* Arbitrary low = off */ + out(0x50 + 2 * sound.channel, rate & 0xFF); + out(0x51 + 2 * sound.channel, rate >> 8); + } + return 0; +} + +int devaudio_ioctl(uarg_t op, void *val) +{ + used(op); + used(val); + return -EINVAL; +} + +void devaudio_tick(void) +{ + if (audio_count[0]) { + if (!--audio_count[0]) { + out(0x51, 0xFF); + wakeup(&audio_count[0]); + } + } + if (audio_count[1]) { + if (!--audio_count[1]) { + out(0x53, 0xFF); + wakeup(&audio_count[1]); + } + } +} + +/* FIXME? - worth making a pwait_irq or similar 'wait for an IRQ to clear + a flag' function ? */ +int devaudio_wait(uint8_t channel) +{ + uint8_t *p = &audio_count[channel]; + irqflags_t irq = di(); + + while(*p) { + if (psleep_flags(p,0) == -1) { + irqrestore(irq); + return -1; + } + } + irqrestore(irq); + return 0; +} diff --git a/Kernel/platform-nc100/devgfx.c b/Kernel/platform-nc100/devgfx.c new file mode 100644 index 00000000..41bd351c --- /dev/null +++ b/Kernel/platform-nc100/devgfx.c @@ -0,0 +1,62 @@ +/* + * Graphics logic for the NC100/200 + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_NC100 +static struct display ncdisplay = { + 480, 64, + 512, 64, + 0xFF, 0xFF, /* For now */ + FMT_MONO_WB, + HW_UNACCEL, + 0, + 0, + GFX_SETPIXEL|GFX_RAW|GFX_RAWCOPY, + 0 +}; +#else +static struct display ncdisplay = { + 480, 128, + 512, 128, + 0xFF, 0xFF, /* For now */ + FMT_MONO_WB, + HW_UNACCEL, + 0, + 0, + GFX_SETPIXEL|GFX_RAW|GFX_RAWCOPY, + 0 +}; +#endif + +extern uint16_t video_op[GFX_BUFLEN]; + +extern struct attribute video_attr; /* Shared with asm code */ + +int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr) +{ + if (arg >> 8 != 0x03) + return vt_ioctl(minor, arg, ptr); + if (arg == GFXIOC_GETINFO) + return uput(&ncdisplay, ptr, sizeof(ncdisplay)); + if (arg == GFXIOC_SETATTR) + return uget(&video_attr, ptr, sizeof(video_attr)); + if (uget(&video_op, ptr, sizeof(video_op))) + return -1; + switch(arg) { + case GFXIOC_SETPIXEL: + video_setpixel(); + return 0; + case GFXIOC_CMD: + video_cmd(); + return 0; + default: + udata.u_error = EINVAL; + return -1; + } +} diff --git a/Kernel/platform-nc100/devgfx.h b/Kernel/platform-nc100/devgfx.h new file mode 100644 index 00000000..f495778c --- /dev/null +++ b/Kernel/platform-nc100/devgfx.h @@ -0,0 +1,13 @@ +#ifndef _DEV_GFX_H +#define _DEV_GFX_H + +#include + +extern int gfx_ioctl(uint8_t minor, uarg_t arg, char *ptr); +extern struct attribute video_attr; +extern uint16_t video_op[GFX_BUFLEN]; + +extern void video_setpixel(void); +extern void video_cmd(void); + +#endif diff --git a/Kernel/platform-nc100/devices.c b/Kernel/platform-nc100/devices.c index bad73e12..6fb58e2b 100644 --- a/Kernel/platform-nc100/devices.c +++ b/Kernel/platform-nc100/devices.c @@ -7,6 +7,7 @@ #include #include #include +#include struct devsw dev_tab[] = /* The device driver switch table */ { @@ -15,7 +16,7 @@ struct devsw dev_tab[] = /* The device driver switch table */ /* 1: /dev/hd Hard disc block devices (Really PCMCIA) */ { rd_open, no_close, rd_read, rd_write, no_ioctl }, /* 2: /dev/tty TTY devices */ - { nc100_tty_open, nc100_tty_close, tty_read, tty_write, vt_ioctl }, + { nc100_tty_open, nc100_tty_close, tty_read, tty_write, gfx_ioctl }, /* 3: /dev/lpr Printer devices */ { lpr_open, lpr_close, no_rdwr, lpr_write, no_ioctl }, /* 4: /dev/mem etc System devices (one offs) */ diff --git a/Kernel/platform-nc100/fuzix.lnk b/Kernel/platform-nc100/fuzix.lnk index b1417305..1c929852 100644 --- a/Kernel/platform-nc100/fuzix.lnk +++ b/Kernel/platform-nc100/fuzix.lnk @@ -31,9 +31,12 @@ bank16k.rel tty.rel vt.rel devsys.rel +audio.rel usermem.rel usermem_std-z80.rel platform-nc100/devlpr.rel platform-nc100/devtty.rel +platform-nc100/devaudio.rel +platform-nc100/devgfx.rel font4x6.rel -e diff --git a/Kernel/platform-nc100/nc100.def b/Kernel/platform-nc100/nc100.def index 5d27681f..297710f0 100644 --- a/Kernel/platform-nc100/nc100.def +++ b/Kernel/platform-nc100/nc100.def @@ -1,3 +1,4 @@ VIDEO_BASEH .equ 0x70 +VIDEO_END .equ 0x80 VIDEO_BASE .equ 0x7000 VIDEO_SIZE .equ 0x1000 diff --git a/Kernel/platform-nc100/nc100.s b/Kernel/platform-nc100/nc100.s index 267057e7..fec413ed 100644 --- a/Kernel/platform-nc100/nc100.s +++ b/Kernel/platform-nc100/nc100.s @@ -32,6 +32,10 @@ .globl _font4x6 .globl _vtinit .globl platform_interrupt_all + .globl _video_setpixel + .globl _video_cmd + .globl _video_attr + .globl _video_op ; exported debugging tools .globl _trap_monitor @@ -62,22 +66,11 @@ ; ----------------------------------------------------------------------------- .area _COMMONMEM -trapmsg: .ascii "Trapdoor: SP=" - .db 0 -trapmsg2: .ascii ", PC=" - .db 0 -tm_user_sp: .dw 0 - -tm_stack: - .db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -tm_stack_top: - _trap_monitor: di halt jr _trap_monitor - _trap_reboot: xor a out (0x70), a @@ -590,3 +583,159 @@ _cursor_off: ld de, (_cursorpos) jr cursor_do +; +; Entered with HL pointing to the co-ordinates +; Returns with HL pointing to the byte address of the pixel +; A holding the pixel mask +; C holding the bit number +; DE holding the screen byte address +; +coords: + ld a, (hl) ; low bits of X + and #7 ; pixel + ld c, a + ld a, (hl) + ld de, #0 ; clear D - and keep D at zero + rra + rra + rra ; A is the byte offset + inc hl + bit 0, (hl) + jr z, xonleft + set 5,a ; right hand side +xonleft: + inc hl + ld a, (hl) ; y low (no y high needed) 0-63 or 0-127 */ + add a ; x 2 + ld l, a + ld h, d ; zero + add hl, hl ; x 4 + add hl, hl ; x 8 + add hl, hl ; x 16 + add hl, hl ; x 32 + add hl, hl ; x 64 lines into bytes offset + add hl, de ; pixel in this byte + ex de, hl + ld hl, #setpixel_bittab + ld b, d ; zero + add hl, bc + ld a, (hl) ; our pixel mask + ex de, hl + ret + +setpixel_optab: + nop ; + or (hl) ; COPY + nop + or (hl) ; SET + cpl ; complement pixel mask + and (hl) ; CLEAR by anding with mask + nop + xor (hl) ; INVERT +setpixel_bittab: + .db 128,64,32,16,8,4,2,1 + +_video_setpixel: + in a, (0x11) + push af + ld a, #0x43 ; Map the display + out (0x11), a + call video_setpixel + pop af + out (0x11), a + ret + +video_setpixel: + ld a, (_video_attr + 2) ; mode + or a ; copy ? + jr nz, setpixel_notdraw + ld a, (_video_attr) ; ink + or a ; white ? + jr nz, setpixel_notdraw ; a = 1 = set so good + ld a, #2 ; clear +setpixel_notdraw: + ld e, a + ld d, #0 + ld hl, #setpixel_optab + add hl, de + ld a, (hl) + ld (setpixel_opcode), a ; Self modifying + inc hl + ld a, (hl) + ld (setpixel_opcode+1), a ; Self modifying + ld bc, (_video_op) ; B is the count + ld a, b + and #0x1f ; max 31 pixels per op + ret z + push bc + ld hl, #_video_op + 2 ; co-ordinate pairs +setpixel_loop: + push hl + call coords +setpixel_opcode: + nop ; nop or cpl + ld a, (hl) ; screen + ld (hl), a ; store back to display + pop hl + inc hl + inc hl + inc hl + inc hl + pop bc + djnz setpixel_loop + ret + +; +; Need different logic for NC200 ? +; +_video_cmd: + in a, (0x11) + push af + ld a, #0x43 ; Map the display + out (0x11), a + call video_cmd + pop af + out (0x11), a + ret + +video_cmd: + ld hl, #_video_op + ld e, (hl) ; offset + inc hl + ld a, (hl) + cp #0x10 + ret nc ; over end + ld d, a + inc hl + ld a, (hl) ; count + cp #124 ; 2 bytes offset, 2 bytes length, 124 data + ret nc + ld c, a + inc hl + ld a, (hl) + or a + ret nz ; too big + ld b, a + push hl + ld l, e + ld h, d + add hl, bc ; end offset + ld a, h + cp #0x10 + jr c, cmd_over ; doesn't fit + ld hl, #VIDEO_BASE + add hl, de ; offset + ex de, hl + pop hl ; input buffer + ldir + ret +cmd_over: pop hl + ret + +; +; Needed here so they don't vanish when we map the screen +; +_video_op: + .ds 128 +_video_attr: + .ds 4