From 906f487b01b172b9f7493d972cfca4a74ed17bb2 Mon Sep 17 00:00:00 2001 From: Bas Wijnen Date: Sun, 4 Oct 2009 19:47:20 +0200 Subject: [PATCH] make more things work --- boot-programs/buzzer.ccp | 138 ++++++++++++ boot-programs/crt0.ccp | 19 ++ boot-programs/devices.hhp | 70 ++++-- boot-programs/init.ccp | 130 +++++++----- boot-programs/init.hhp | 60 ------ boot-programs/nanonote-gpio.ccp | 366 ++++++++++++++++++++++++++++++++ boot-programs/udc.ccp | 43 ++-- invoke.ccp | 18 ++ iris.hhp | 7 + kernel.hhp | 1 + mips/arch.ccp | 12 ++ mips/nanonote/Makefile.arch | 8 +- mips/nanonote/board.ccp | 1 + mips/nanonote/jz4740.hhp | 103 ++++++++- mips/nanonote/nanonote-boot.ccp | 17 +- mips/nanonote/sdram-setup.ccp | 108 +--------- mips/nanonote/threadlist.S | 10 + panic.ccp | 3 + plan | 26 +++ 19 files changed, 872 insertions(+), 268 deletions(-) create mode 100644 boot-programs/buzzer.ccp delete mode 100644 boot-programs/init.hhp create mode 100644 boot-programs/nanonote-gpio.ccp diff --git a/boot-programs/buzzer.ccp b/boot-programs/buzzer.ccp new file mode 100644 index 0000000..0fbea4f --- /dev/null +++ b/boot-programs/buzzer.ccp @@ -0,0 +1,138 @@ +#pypp 0 +// Iris: micro-kernel for a capability-based operating system. +// boot-programs/buzzer.ccp: Piezo buzzer driver. +// Copyright 2009 Bas Wijnen +// +// This program 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 3 of the License, or +// (at your option) any later version. +// +// This program 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 program. If not, see . + +#include "devices.hh" +#define ARCH +#include "arch.hh" + +class DevBuzzer: + static unsigned const pwm = 4 + Kernel::Cap event + bool is_active, is_beeping + public: + DevBuzzer (): + is_active = false + is_beeping = false + gpio_as_pwm4 () + tcu_stop_counter (pwm) + tcu_select_extalclk (pwm) + tcu_select_clk_div64 (pwm) + tcu_enable_pwm_output (pwm) + void stop (): + if !is_beeping: + return + tcu_stop_counter (pwm) + event.invoke () + is_active = false + Kernel::free_cap (event) + void beep (unsigned freq, unsigned ms, Kernel::Cap cb): + stop () + event = cb + unsigned full = JZ_EXTAL / 64 / freq + tcu_set_full_data (pwm, full) + tcu_set_half_data (pwm, full / 2) + tcu_set_count (pwm, 0) + tcu_start_counter (pwm) + Kernel::my_receiver.set_alarm (ms * HZ / 1000) + is_beeping = true + +enum codes: + BUZZER = 32 + +Kernel::Num start (): + map_gpio () + map_tcu () + + DevBuzzer buzzer + + Device dev = Kernel::my_receiver.create_capability (BUZZER) + Kernel::my_parent.ocall (dev.copy (), Buzzer::ID) + Kernel::free_cap (dev) + unsigned user (~0) + unsigned next_user (0) + while true: + Kernel::wait () + switch Kernel::recv.protected_data.h: + case ~0: + // Alarm. + buzzer.stop () + break + case 0: + switch Kernel::recv.protected_data.l: + case BUZZER: + // Buzzer device control request. + switch Kernel::recv.data[0].l: + case Device::CREATE_USER: + Kernel::Cap reply = Kernel::get_reply () + Keyboard cap = Kernel::my_receiver.create_capability (Kernel::Num (next_user++, BUZZER)) + reply.invoke (0, 0, cap.copy ()) + Kernel::free_cap (cap) + Kernel::free_cap (reply) + break + case Device::DESTROY_USER: + Kernel::recv.reply.invoke () + break + case Device::UNUSE: + buzzer.stop () + Kernel::recv.reply.invoke () + break + case Device::USE: + Kernel::Cap reply = Kernel::get_reply () + user = Kernel::my_receiver.get_protected (Kernel::recv.arg).l + reply.invoke () + Kernel::free_cap (reply) + break + default: + kdebug ("invalid buzzer control command: ") + kdebug_num (Kernel::recv.data[0].l) + kdebug ("\n") + break + break + default: + kdebug ("invalid buzzer request\n") + break + break + case BUZZER: + // Buzzer device user request. + if Kernel::recv.protected_data.l != user: + kdebug ("invalid user requesting buzzer\n") + Kernel::recv.reply.invoke () + break + switch Kernel::recv.data[0].l: + case Buzzer::BEEP: + // Volume is not used for this buzzer. + Kernel::Cap arg = Kernel::get_arg () + Kernel::Cap reply = Kernel::get_reply () + buzzer.beep (Kernel::recv.data[1].l, Kernel::recv.data[1].h, arg) + reply.invoke () + Kernel::free_cap (arg) + Kernel::free_cap (reply) + break + case Buzzer::STOP: + kdebug ("stop\n") + buzzer.stop () + Kernel::recv.reply.invoke () + break + default: + kdebug ("other\n") + break + break + default: + kdebug ("unknown num: ") + kdebug_num (Kernel::recv.protected_data.h) + kdebug ("\n") diff --git a/boot-programs/crt0.ccp b/boot-programs/crt0.ccp index 2d71f6e..efd1702 100644 --- a/boot-programs/crt0.ccp +++ b/boot-programs/crt0.ccp @@ -36,7 +36,23 @@ namespace Kernel: Cap my_parent __recv_data_t recv + void print_caps (): + // Assume __caps to be 16. + bool used[16] + for unsigned i = 0; i < 16; ++i: + used[i] = true + unsigned num = 0 + for list *i = __first_free_cap; i; i = i->next: + used[i - __cap_admin] = false + ++num + kdebug_num (num, 1) + kdebug (":") + for unsigned i = 0; i < 16; ++i: + kdebug_char (used[i] ? '#' : '.') + kdebug_char ('\n') + void free_slot (unsigned slot): + //kdebug ("free slot\n") __slot_admin[slot].prev = NULL __slot_admin[slot].next = __first_free_slot if __slot_admin[slot].next: @@ -44,6 +60,7 @@ namespace Kernel: __first_free_slot = &__slot_admin[slot] void free_cap (Cap cap): + //kdebug ("free cap\n") if cap.slot () != 0: kdebug ("trying to free capability from non-0 slot\n") return @@ -55,6 +72,7 @@ namespace Kernel: __first_free_cap = l unsigned alloc_slot (): + //kdebug ("alloc slot\n") if !__first_free_slot: // Out of slots... Probably best to raise an exception. For now, just return NO_SLOT. kdebug ("out of slots!\n") @@ -66,6 +84,7 @@ namespace Kernel: return ret - __slot_admin Cap alloc_cap (): + //kdebug ("alloc cap\n") if !__first_free_cap: // Out of caps... Probably best to raise an exception. For now, just return CAP_NONE kdebug ("out of capabilities!\n") diff --git a/boot-programs/devices.hhp b/boot-programs/devices.hhp index ff12a9e..38fb9e8 100644 --- a/boot-programs/devices.hhp +++ b/boot-programs/devices.hhp @@ -39,7 +39,7 @@ struct String : public Kernel::Cap: GET_SIZE = 0x2001 GET_CHARS GET_PAGE - _END_MARKER + ID /// Get the size of the string. Kernel::Num get_size (): return call (CAP_MASTER_DIRECT | GET_SIZE) @@ -61,10 +61,10 @@ struct String : public Kernel::Cap: struct WString : public String: WString (Kernel::Cap c = Kernel::Cap ()) : String (c): enum request: - TRUNCATE = String::_END_MARKER + TRUNCATE = String::ID SET_CHARS SET_PAGE - _END_MARKER + ID /// Set the size of the string. Strings may have a limit to this setting. void truncate (Kernel::Num size): call (CAP_MASTER_DIRECT | TRUNCATE, size) @@ -75,17 +75,41 @@ struct WString : public String: void set_page (Kernel::Num idx, Kernel::Page page): ocall (page, CAP_MASTER_DIRECT | SET_PAGE, idx) +// Every process which wants to be switchable through a terminal must implement this interface. +struct Device : public Kernel::Cap: + Device (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): + enum request: + CREATE_USER = WString::ID + DESTROY_USER + UNUSE + USE + ID + // Create a new user for this device. It will not be the active user. + // The provided storage must allow object creation; no other actions may be used by the terminal. + Kernel::Cap create_user (Kernel::Memory storage): + iocall (storage, CAP_MASTER_DIRECT | CREATE_USER) + return Kernel::get_arg () + // Destroy a user. It must not be active. + void destroy_user (Kernel::Cap user): + ocall (user, CAP_MASTER_DIRECT | DESTROY_USER) + // Make user inactive. + void unuse (Kernel::Cap user): + ocall (user, CAP_MASTER_DIRECT | UNUSE) + // Make user active. + void use (Kernel::Cap user): + ocall (user, CAP_MASTER_DIRECT | USE) + // Keyboard interface. struct Keyboard : public Kernel::Cap: Keyboard (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): enum request: - SET_CB = WString::_END_MARKER + SET_CB = Device::ID GET_KEYS - _END_MARKER + ID // At event: the callback is called with a keycode. One bit defines if it's a press or release event. enum constant: RELEASE = 1 << 31 - // Set the event callback. Currently pressed keys emit a key press event to the new callback immediately, plus a ~0 to signal the end of such events. + // Set the event callback. Currently pressed keys emit a key press event to the new callback immediately. void set_cb (Kernel::Cap cb): ocall (cb, CAP_MASTER_DIRECT | SET_CB) // Get a list of keys on this keyboard. The key codes start at zero with no gaps. @@ -93,15 +117,29 @@ struct Keyboard : public Kernel::Cap: icall (CAP_MASTER_DIRECT | GET_KEYS) return List (Kernel::get_arg ()) +// Buzzer interface. +struct Buzzer : public Kernel::Cap: + Buzzer (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): + enum request: + BEEP = Keyboard::ID + STOP + ID + // Emit a beep of specified frequency, time and volume. Volume may not be supported. + void beep (unsigned freq, unsigned ms, unsigned volume, Kernel::Cap cb = Kernel::Cap ()): + ocall (cb, Kernel::Num (CAP_MASTER_DIRECT | BEEP, volume), Kernel::Num (freq, ms)) + // Abort current beep, if any. + void stop (): + call (CAP_MASTER_DIRECT | STOP) + // Display interface. struct Display : public Kernel::Cap: Display (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): enum request: - EOF_CB = Keyboard::_END_MARKER + EOF_CB = Buzzer::ID CREATE_FB USE_FB GET_INFO - _END_MARKER + ID // Register an end-of-frame callback. // At end of frame, the callback is invoked and forgotten. It must be reregistered to keep a stream of events. void set_eof_cb (Kernel::Cap cb): @@ -129,10 +167,10 @@ struct Display : public Kernel::Cap: struct File : public Kernel::Cap: File (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): enum request: - INFO = Display::_END_MARKER + INFO = Display::ID CLOSE MAP_HANDLE - _END_MARKER + ID // Get information about the file. Kernel::Num get_info (unsigned type): return icall (Kernel::Num (CAP_MASTER_DIRECT | INFO, type)) @@ -148,13 +186,13 @@ struct File : public Kernel::Cap: struct Directory : public File: Directory (Kernel::Cap c = Kernel::Cap ()) : File (c): enum request: - GET_SIZE = File::_END_MARKER + GET_SIZE = File::ID GET_NAME GET_FILE GET_FILE_INFO CREATE_FILE DELETE_FILE - _END_MARKER + ID // Get the number of entries in this directory. Kernel::Num get_size (): return call (CAP_MASTER_DIRECT | GET_SIZE) @@ -181,9 +219,9 @@ struct Directory : public File: struct Stream : public File: Stream (Kernel::Cap c = Kernel::Cap ()) : File (c): enum request: - READ = Directory::_END_MARKER + READ = Directory::ID WRITE - _END_MARKER + ID // Try to read size bytes. Returns the number of bytes successfully read. Kernel::Num read (Kernel::Num size): return icall (CAP_MASTER_DIRECT | READ, size) @@ -195,10 +233,10 @@ struct Stream : public File: struct Seekable : public File: Seekable (Kernel::Cap c = Kernel::Cap ()) : File (c): enum request: - READ = Stream::_END_MARKER + READ = Stream::ID WRITE TRUNCATE - _END_MARKER + ID // Try to read size bytes from position idx. Returns the number of bytes successfully read. Kernel::Num read (Kernel::Num idx, unsigned size): return icall (Kernel::Num (CAP_MASTER_DIRECT | READ, size), idx) diff --git a/boot-programs/init.ccp b/boot-programs/init.ccp index 46a072b..e996ad2 100644 --- a/boot-programs/init.ccp +++ b/boot-programs/init.ccp @@ -18,84 +18,114 @@ #include "devices.hh" #include "iris.hh" -#include "init.hh" -static Keyboard kbd, tp -static Display lcd -static Kernel::Cap lockleds, pwm +static Keyboard kbd, sysreq +static Buzzer buzzer +static Device kbd_dev, buz_dev +static List kbd_names +static unsigned slot // Event types. enum type: - KBD = 0x10000 - TP + MEMORY + KBDDEV + KBD + KEYNAMES + SYSREQ + BUZDEV + BUZZER static void setup (): unsigned state = 0 - Kernel::Caps my_caps = Kernel::my_memory.create_caps (4 + 1) - unsigned my_slot = my_caps.use () - unsigned slot = Kernel::alloc_slot () + Kernel::Caps caps = Kernel::my_memory.create_caps (32) + slot = caps.use () + Kernel::set_recv_arg (Kernel::Cap (slot, MEMORY)) + Kernel::Cap driver_memory = Kernel::my_memory.create_memory () while true: Kernel::wait () Kernel::Cap reply = Kernel::get_reply () - Kernel::Caps caps = Kernel::get_arg () - switch Kernel::recv.data[0].value (): - case Init::REGISTER_GPIO: - caps.use (slot) - for unsigned i = 0; i < 4; ++i: - my_caps.set (i, Kernel::Cap (slot, i).copy ()) - kbd = Kernel::Cap (my_slot, 0) - tp = Kernel::Cap (my_slot, 1) - lockleds = Kernel::Cap (my_slot, 2) - pwm = Kernel::Cap (my_slot, 3) + Kernel::Cap arg = Kernel::get_arg () + switch Kernel::recv.data[0].l: + case Keyboard::ID: + switch Kernel::recv.data[0].h: + case 0: + caps.set (KBDDEV, arg.copy ()) + kbd_dev = Kernel::Cap (slot, KBDDEV) + break + case 1: + caps.set (SYSREQ, arg.copy ()) + sysreq = Kernel::Cap (slot, SYSREQ) + break + default: + kdebug ("unexpected keyboard\n") + break break - case Init::REGISTER_LCD: - caps.use (slot) - my_caps.set (4, Kernel::Cap (slot, 0).copy ()) - lcd = Kernel::Cap (my_slot, 4) + case Buzzer::ID: + caps.set (BUZDEV, arg.copy ()) + buz_dev = Kernel::Cap (slot, BUZDEV) break default: + Kernel::free_cap (reply) + Kernel::free_cap (arg) kdebug ("unknown setup request for init\n") continue reply.invoke () - Kernel::free_cap (caps) Kernel::free_cap (reply) - if ++state == 2: + Kernel::free_cap (arg) + if ++state == 3: break - Kernel::free_cap (my_caps) - Kernel::free_slot (slot) - Kernel::schedule () - Kernel::Cap kc = Kernel::my_receiver.create_capability (KBD) - kbd.set_cb (kc) - Kernel::Cap tc = Kernel::my_receiver.create_capability (TP) - tp.set_cb (tc) - pwm.call (1) + // sysreq + Kernel::Cap cb = Kernel::my_receiver.create_capability (SYSREQ) + sysreq.set_cb (cb.copy ()) + // keyboard user + Kernel::set_recv_arg (Kernel::Cap (slot, KBD)) + kbd = kbd_dev.create_user (driver_memory) + kbd_dev.use (kbd) + // keyboard callback + Kernel::set_recv_arg (cb) + Kernel::my_receiver.create_capability (KBD) + kbd.set_cb (cb.copy ()) + // keyboard name list + Kernel::set_recv_arg (Kernel::Cap (slot, KEYNAMES)) + kbd_names = kbd.get_keys () + // buzzer user + Kernel::set_recv_arg (Kernel::Cap (slot, BUZZER)) + buzzer = buz_dev.create_user (driver_memory) + buz_dev.use (buzzer) + // clean up. + Kernel::free_cap (cb) -char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":" +//char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$%^&*() T\n[],.-=/\\;|`'UDLREIKBPFZMS{}CA\":" +char const *decode_kbd = "0123456789abcdefghijklmnopqrstuvwxyz!@#$*T\nE& B=UDLR+-F^CA" Kernel::Num start (): - kdebug ("init started\n") setup () kdebug ("init set up\n") while true: - kdebug ("init waiting\n") Kernel::wait () - kdebug ("init done waiting\n") switch Kernel::recv.protected_data.value (): + case SYSREQ: + unsigned code = Kernel::recv.data[0].l + kdebug ("\n\nSystem request ") + if code & Keyboard::RELEASE: + kdebug ("released.\n\n") + else: + kdebug ("pressed.\n\n") + break case KBD: unsigned code = Kernel::recv.data[0].l if code & Keyboard::RELEASE: - break - kdebug_char (decode_kbd[code]) - if code == 0: - Kernel::Caps ().print (~0) - break - case TP: - unsigned leds = 0 - if Kernel::recv.data[0].l & 1: - leds |= 0x1 + kdebug_char ('-') else: - leds |= 0x4 - if !(Kernel::recv.data[0].l & Keyboard::RELEASE): - leds |= 0x2 - lockleds.call (leds) + kdebug_char ('+') + buzzer.beep (2000, 100, 0) + String name = kbd_names.get (code & ~Keyboard::RELEASE) + unsigned size = name.get_size ().l + char buffer[16] + for unsigned i = 0; i < size; i += 16: + name.get_chars (i, buffer) + for unsigned k = 0; k < size - i && k < 16; ++k: + kdebug_char (buffer[k]) + kdebug_char ('\n') + Kernel::free_cap (name) break diff --git a/boot-programs/init.hhp b/boot-programs/init.hhp deleted file mode 100644 index b3b11fb..0000000 --- a/boot-programs/init.hhp +++ /dev/null @@ -1,60 +0,0 @@ -#pypp 0 -// Iris: micro-kernel for a capability-based operating system. -// boot-programs/init.hhp: interface for init task. -// Copyright 2009 Bas Wijnen -// -// This program 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 3 of the License, or -// (at your option) any later version. -// -// This program 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 program. If not, see . - -#ifndef __INIT_HH -#define __INIT_HH - -#include "iris.hh" - -struct Init : public Kernel::Cap: - Init (Kernel::Cap c = Kernel::Cap ()) : Kernel::Cap (c): - enum request: - REGISTER_GPIO = 0x1000 - REGISTER_LCD - enum protected_codes: - GPIO_KEYBOARD = 32 - GPIO_TOUCHPAD - GPIO_LOCKLEDS - GPIO_PWM - LCD_SET_EOF_CB - LOG - void register_gpio (): - Kernel::Caps c = Kernel::my_memory.create_caps (4) - unsigned slot = c.use () - Kernel::set_recv_arg (Kernel::Cap (slot, 0)) - Kernel::my_receiver.create_capability (GPIO_KEYBOARD) - Kernel::set_recv_arg (Kernel::Cap (slot, 1)) - Kernel::my_receiver.create_capability (GPIO_TOUCHPAD) - Kernel::set_recv_arg (Kernel::Cap (slot, 2)) - Kernel::my_receiver.create_capability (GPIO_LOCKLEDS) - Kernel::set_recv_arg (Kernel::Cap (slot, 3)) - Kernel::my_receiver.create_capability (GPIO_PWM) - ocall (c, CAP_MASTER_DIRECT | REGISTER_GPIO) - Kernel::my_memory.destroy (c) - Kernel::free_cap (c) - Kernel::free_slot (slot) - void register_lcd (): - Kernel::Caps c = Kernel::my_memory.create_caps (1) - unsigned slot = c.use () - Kernel::set_recv_arg (Kernel::Cap (slot, 0)) - Kernel::my_receiver.create_capability (LCD_SET_EOF_CB) - ocall (c, CAP_MASTER_DIRECT | REGISTER_LCD) - Kernel::my_memory.destroy (c) - Kernel::free_cap (c) - Kernel::free_slot (slot) -#endif diff --git a/boot-programs/nanonote-gpio.ccp b/boot-programs/nanonote-gpio.ccp new file mode 100644 index 0000000..64a3cee --- /dev/null +++ b/boot-programs/nanonote-gpio.ccp @@ -0,0 +1,366 @@ +#pypp 0 +// Iris: micro-kernel for a capability-based operating system. +// boot-programs/nanonote-gpio.ccp: gpio devices on the nanonote. +// Copyright 2009 Bas Wijnen +// +// This program 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 3 of the License, or +// (at your option) any later version. +// +// This program 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 program. If not, see . + +#include "devices.hh" +#define ARCH +#include "arch.hh" + +//#define QI +#define SCAN_INTERVAL HZ / 50 + +class DevKbd: + static unsigned const NUM_COLS = 8 + static unsigned const NUM_ROWS = 8 + static unsigned const COLS_PORT = 2 + static unsigned const ROWS_PORT = 3 + static unsigned const ALL_COLS = 0x0003fc00 + static unsigned const ALL_ROWS = 0x05fc0000 + static unsigned const COLS[NUM_COLS] + static unsigned const ROWS[NUM_ROWS] + static unsigned const encode[NUM_ROWS][NUM_COLS] + enum Keys: + #ifdef QI + A, B, C, D, E, F, G, H, I, J, K, L, M + N, O, P, Q, R, S, T, U, V, W, X, Y, Z + F1, F2, F3, F4, F5, F6, F7, F8 + TAB, BACKSLASH, QUOTE, COMMA, PERIOD, SLASH, EQUAL, SPACE + ESCAPE, ENTER, BACKSPACE + UP, DOWN, LEFT, RIGHT + CAPS, ARROW, QI, CTRL, VOLUP, VOLDOWN, SHIFT, ALT, FN + #else + N0, N1, N2, N3, N4, N5, N6, N7, N8, N9 + A, B, C, D, E, F, G, H, I, J, K, L, M + N, O, P, Q, R, S, T, U, V, W, X, Y, Z + F1, F2, F3, F4 + CAPS, TAB, ENTER, ESCAPE, MP3, SPACE, BACKSPACE, EQUALS + UP, DOWN, LEFT, RIGHT + VOLUP, VOLDOWN + FN, SHIFT, CTRL, ALT + #endif + NUM_KEYS + static char const *const names[NUM_KEYS] + unsigned state[NUM_COLS] + Kernel::Cap event + bool is_active + bool is_scanning + public: + unsigned size (): + return NUM_KEYS + unsigned get_name_size (unsigned n): + if n >= NUM_KEYS: + return 0 + unsigned ret = 0 + for char const *p = names[n]; *p; ++p: + ++ret + return ret + void send_name (unsigned n, Kernel::Cap c, Kernel::Num offset): + if n >= NUM_KEYS: + c.invoke (0, 0) + return + unsigned data[4] + char *d = (char *)data + if offset.value () < get_name_size (n): + unsigned o = offset.l & ~3; + unsigned p + for p = 0; p < 16 && names[n][p + o]; ++p: + *d++ = names[n][p + o] + for ; p < 16; ++p: + *d++ = 0 + c.invoke (Kernel::Num (data[0], data[1]), Kernel::Num (data[2], data[3])) + bool scanning (): + return is_scanning + void inactive (): + if is_active: + Kernel::free_cap (event) + is_active = false + void check (unsigned col, unsigned rowdata): + for unsigned r = 0; r < NUM_ROWS; ++r: + if !((rowdata ^ state[col]) & (1 << ROWS[r])): + continue + unsigned code = encode[r][col] + if rowdata & (1 << ROWS[r]): + code |= Keyboard::RELEASE + if is_active: + event.invoke (code) + state[col] = rowdata + void delay (): + for unsigned i = 0; i < 10000; ++i: + gpio_set (0, 0) + void scan (): + unsigned r + gpio_mask_irq (ROWS_PORT, ALL_ROWS) + is_scanning = false + if !is_active: + return + for unsigned c = 0; c < NUM_COLS; ++c: + gpio_as_input (COLS_PORT, ALL_COLS & ~(1 << COLS[c])) + gpio_as_output (COLS_PORT, 1 << COLS[c]) + if c > 0: + check (c - 1, r) + delay () + else: + check (0, state[0]) + delay () + r = gpio_get_port (ROWS_PORT) & ALL_ROWS + if r != ALL_ROWS: + is_scanning = true + gpio_as_output (COLS_PORT, ALL_COLS) + check (NUM_COLS - 1, r) + delay () + r = gpio_get_port (ROWS_PORT) & ALL_ROWS + unsigned high = 0, low = 0 + for unsigned i = 0; i < NUM_ROWS; ++i: + if r & (1 << ROWS[i]): + low |= 1 << ROWS[i] + else: + high |= 1 << ROWS[i] + gpio_as_interrupt (ROWS_PORT, high, true, true) + gpio_as_interrupt (ROWS_PORT, low, false, true) + gpio_unmask_irq (ROWS_PORT, ALL_ROWS) + void active (Kernel::Cap cb): + inactive () + event = cb + is_active = true + for unsigned c = 0; c < NUM_COLS; ++c: + state[c] = ALL_ROWS + scan () + DevKbd (): + is_active = false + gpio_as_gpio (COLS_PORT, ALL_COLS) + gpio_as_gpio (ROWS_PORT, ALL_ROWS) + gpio_clear (COLS_PORT, ALL_COLS) + gpio_as_output (COLS_PORT, ALL_COLS) + gpio_as_input (ROWS_PORT, ALL_ROWS) + gpio_enable_pull (ROWS_PORT, ALL_ROWS) + for unsigned i = 0; i < NUM_COLS; ++i: + state[i] = ALL_ROWS + scan () + +unsigned const DevKbd::COLS[NUM_COLS] = { 10, 11, 12, 13, 14, 15, 16, 17 } +unsigned const DevKbd::ROWS[NUM_ROWS] = { 18, 19, 20, 21, 22, 23, 24, 26 } +unsigned const DevKbd::encode[NUM_ROWS][NUM_COLS] = { + #ifdef QI + { F1, F2, F3, F4, F5, F6, F7, ~0 }, + { Q, W, E, R, T, Y, U, I }, + { A, S, D, F, G, H, J, K }, + { ESCAPE, Z, X, C, V, B, N, M }, + { TAB, CAPS, BACKSLASH, QUOTE, COMMA, PERIOD, SLASH, UP }, + { O, L, EQUAL, ARROW, SPACE, QI, CTRL, LEFT }, + { F8, P, BACKSPACE, ENTER, VOLUP, VOLDOWN, DOWN, RIGHT }, + { SHIFT, ALT, FN, ~0, ~0, ~0, ~0, ~0 } + #else + { ESCAPE, TAB, F1, F2, F3, F4, MP3, ~0 }, + { N1, N2, N3, N4, N5, N6, N7, N8 }, + { Q, W, E, R, T, Y, U, I }, + { A, S, D, F, G, H, J, K }, + { Z, X, C, V, B, N, M, UP }, + { N9, O, L, ALT, CAPS, SPACE, EQUALS, LEFT }, + { BACKSPACE, N0, P, ENTER, VOLUP, VOLDOWN, DOWN, RIGHT }, + { FN, SHIFT, CTRL, ~0, ~0, ~0, ~0, ~0 } + #endif + } +char const *const DevKbd::names[NUM_KEYS] = { + #ifdef QI + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", + "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", + "tab", "\\", "'", ",", ".", "/", "=", "space", + "escape", "enter", "backspace", + "up", "down", "left", "right", + "caps lock", "arrow", "qi", "left control", "volume up", "volume down", "left shift", "left alt", "fn" + #else + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", + "f1", "f2", "f3", "f4", + "caps lock", "tab", "enter", "escape", "mp3", "space", "backspace", "=", + "up", "down", "left", "right", + "volume up", "volume down", + "fn", "left shift", "left control", "left alt" + #endif + } + +class PowerButton: + bool state, started + Kernel::Cap cb + public: + void scan (): + gpio_mask_irq (3, 1 << 29) + bool s = gpio_get_port (3) & (1 << 29) + if s != state: + state = s + cb.invoke (state ? Keyboard::RELEASE : 0) + gpio_as_interrupt (3, 1 << 29, !state, true) + gpio_unmask_irq (3, 1 << 29) + PowerButton (): + gpio_as_gpio (3, 29) + state = true + started = false + void set_cb (Kernel::Cap c): + if started: + Kernel::free_cap (cb) + else: + started = true + cb = c + state = true + scan () + +enum codes: + KBD_DEV = 32 + KBD_LIST + PWR + +Kernel::Num start (): + map_gpio () + map_tcu () + + DevKbd kbd + PowerButton pwr + + Device dev = Kernel::my_receiver.create_capability (KBD_DEV) + Keyboard pw = Kernel::my_receiver.create_capability (PWR) + Kernel::my_parent.ocall (dev.copy (), Kernel::Num (Keyboard::ID, 0)) + Kernel::my_parent.ocall (pw.copy (), Kernel::Num (Keyboard::ID, 1)) + Kernel::free_cap (dev) + Kernel::free_cap (pw) + if kbd.scanning (): + Kernel::my_receiver.set_alarm (SCAN_INTERVAL) + unsigned user (~0) + unsigned next_user (0) + List list = List (Kernel::my_receiver.create_capability (KBD_LIST)) + Kernel::register_interrupt (IRQ_GPIO3) + while true: + Kernel::wait () + switch Kernel::recv.protected_data.h: + case ~0: + // Alarm. + kbd.scan () + if kbd.scanning (): + Kernel::my_receiver.set_alarm (SCAN_INTERVAL) + break + case 0: + switch Kernel::recv.protected_data.l: + case IRQ_GPIO3: + // Interrupt. + pwr.scan () + kbd.scan () + if kbd.scanning (): + Kernel::my_receiver.set_alarm (SCAN_INTERVAL) + Kernel::register_interrupt (IRQ_GPIO3) + break + case PWR: + // Power button request. + switch Kernel::recv.data[0].l: + case Keyboard::SET_CB: + pwr.set_cb (Kernel::get_arg ()) + Kernel::recv.reply.invoke () + break + default: + kdebug ("power button invalid request\n") + break + break + case KBD_DEV: + // Keyboard device control request. + switch Kernel::recv.data[0].l: + case Device::CREATE_USER: + kdebug ("create\n") + Kernel::Cap reply = Kernel::get_reply () + Keyboard cap = Kernel::my_receiver.create_capability (Kernel::Num (next_user++, KBD_DEV)) + reply.invoke (0, 0, cap.copy ()) + Kernel::free_cap (cap) + Kernel::free_cap (reply) + break + case Device::DESTROY_USER: + kdebug ("destroy\n") + Kernel::recv.reply.invoke () + break + case Device::UNUSE: + kdebug ("unuse\n") + kbd.inactive () + Kernel::recv.reply.invoke () + break + case Device::USE: + kdebug ("use\n") + Kernel::Cap reply = Kernel::get_reply () + user = Kernel::my_receiver.get_protected (Kernel::recv.arg).l + reply.invoke () + Kernel::free_cap (reply) + break + default: + kdebug ("other dev:") + kdebug_num (Kernel::recv.data[0].l) + kdebug ("\n") + break + break + case KBD_LIST: + // Keyboard name lookup. + switch Kernel::recv.data[0].l: + case Kernel::Caps::GET: + Kernel::Cap reply = Kernel::get_reply () + unsigned num = Kernel::recv.data[1].l + Kernel::Cap name = Kernel::my_receiver.create_capability (Kernel::Num (num, KBD_LIST)) + reply.invoke (kbd.get_name_size (num), 0, name.copy ()) + Kernel::free_cap (name) + Kernel::free_cap (reply) + break + case Kernel::Caps::GET_SIZE: + Kernel::recv.reply.invoke (kbd.size ()) + break + default: + kdebug ("invalid list operation\n") + break + break + default: + break + break + case KBD_DEV: + // Keyboard device user request. + if Kernel::recv.protected_data.l != user: + kdebug ("invalid user requesting\n") + Kernel::recv.reply.invoke () + break + switch Kernel::recv.data[0].l: + case Keyboard::SET_CB: + kdebug ("set cb\n") + kbd.active (Kernel::get_arg ()) + Kernel::recv.reply.invoke () + break + case Keyboard::GET_KEYS: + kdebug ("get keys\n") + Kernel::recv.reply.invoke (0, 0, list) + break + default: + kdebug ("other\n") + break + break + case KBD_LIST: + switch Kernel::recv.data[0].l: + case String::GET_SIZE: + Kernel::recv.reply.invoke (kbd.get_name_size (Kernel::recv.protected_data.l)) + break + case String::GET_CHARS: + kbd.send_name (Kernel::recv.protected_data.l, Kernel::recv.reply, Kernel::recv.data[1]) + break + default: + kdebug ("invalid string operation\n") + break + break + default: + kdebug ("unknown num: ") + kdebug_num (Kernel::recv.protected_data.h) + kdebug ("\n") diff --git a/boot-programs/udc.ccp b/boot-programs/udc.ccp index e9494f3..8af41e6 100644 --- a/boot-programs/udc.ccp +++ b/boot-programs/udc.ccp @@ -17,7 +17,6 @@ // along with this program. If not, see . #include "devices.hh" -#include "init.hh" #define ARCH #include "arch.hh" @@ -130,6 +129,7 @@ class Udc: char configuration unsigned size char const *ptr + bool rebooting bool vendor (Setup *s) bool get_descriptor (unsigned type, unsigned idx, unsigned len) bool handle_setup (Setup *s) @@ -149,7 +149,6 @@ Udc::my_config const Udc::config_descriptor = { Udc::String <7> const Udc::s_manufacturer = { sizeof (String <7>), String <7>::Type, { 'I', 'n', 'g', 'e', 'n', 'i', 'c' } } Udc::String <22> const Udc::s_product = { sizeof (String <22>), String <22>::Type, { 'J', 'Z', '4', '7', '4', '0', ' ', 'U', 'S', 'B', ' ', 'B', 'o', 'o', 't', ' ', 'D', 'e', 'v', 'i', 'c', 'e'} } void Udc::init (): - kdebug ("udc: init\n") state = IDLE configuration = 0 size = 0 @@ -165,19 +164,16 @@ void Udc::init (): UDC_INDEX = 0 bool Udc::vendor (Setup *s): - kdebug ("udc: vendor\n") if s->request_type & 0x80: - kdebug ("udc: vendorsend\n") static char const *name = "abcdefgh" ptr = name size = 8 state = TX + rebooting = true return true - kdebug ("udc: vendorrecv\n") return true bool Udc::get_descriptor (unsigned type, unsigned idx, unsigned len): - kdebug ("udc: getdesc\n") switch type: case Configuration::Type: if idx != 1: @@ -268,7 +264,6 @@ bool Udc::handle_setup (Setup *s): return true void Udc::interrupt (): - kdebug ("udc: inter\n") unsigned i = UDC_INTRUSB if i & UDC_INTR_RESET: kdebug ("udc: reset\n") @@ -276,7 +271,6 @@ void Udc::interrupt (): return i = UDC_INTRIN if i & (1 << 0): - kdebug ("udc: ep0\n") // Interrupt on endpoint 0. unsigned csr = UDC_CSR0 if csr & UDC_CSR0_SENTSTALL: @@ -287,10 +281,10 @@ void Udc::interrupt (): state = IDLE switch state: case IDLE: - kdebug ("udc: idle\n") + if rebooting: + Kernel::reboot () if !(csr & UDC_CSR0_OUTPKTRDY): return - kdebug ("udc: packet\n") union { unsigned d[2]; Setup s; } packet packet.d[0] = UDC_FIFO (0) packet.d[1] = UDC_FIFO (0) @@ -327,30 +321,41 @@ void Udc::interrupt (): UDC_CSR0 = csr void Udc::log (unsigned c): - kdebug ("udc: log\n") + kdebug ("udc: log ") + kdebug_char (c) + kdebug ("\n") + +enum pdata: + LOG = 32 Kernel::Num start (): map_udc () + map_gpio () Udc udc - kdebug ("udc: start\n") udc.init () - kdebug ("udc: done init\n") - Kernel::Cap logcap = Kernel::my_receiver.create_capability (Init::LOG) - kdebug ("udc: made cap\n") + Kernel::Cap logcap = Kernel::my_receiver.create_capability (LOG) __asm__ volatile ("li $a0, 1\nlw $a1, %0\nbreak" :: "m"(logcap.code): "a0", "a1", "memory") - kdebug ("udc: registered cap\n") Kernel::register_interrupt (IRQ_UDC) - kdebug ("udc: registered interrupt\n") + //Kernel::my_receiver.set_alarm (HZ) while true: - kdebug ("udc: waiting\n") Kernel::wait () switch Kernel::recv.protected_data.l: + case ~0: + // alarm. + Kernel::my_receiver.set_alarm (HZ) + kdebug ("alarm; d =") + unsigned mask[4] = { 0x00000000, 0xfe000000, 0x09c00000, 0x3dfc8055 } + for unsigned i = 0; i < 4; ++i: + kdebug (" ") + kdebug_num (gpio_get_port (i) & mask[i]) + kdebug ("\n") + break case IRQ_UDC: udc.interrupt () Kernel::register_interrupt (IRQ_UDC) break - case Init::LOG: + case LOG: udc.log (Kernel::recv.data[0].l) break default: diff --git a/invoke.ccp b/invoke.ccp index fda3d2d..b22beaa 100644 --- a/invoke.ccp +++ b/invoke.ccp @@ -168,6 +168,15 @@ static kCaps reply_caps, replied_caps static kReceiver *reply_target static Kernel::Num reply_protected +static void reply_num (Kernel::Num num): + kCapability::Context c + c.data[0] = num + c.data[1] = 0 + if reply_target: + reply_target->send_message (reply_protected, &c) + else: + dpanic (0, "nothing to reply to") + static void reply_num (unsigned num1, unsigned num2 = 0, unsigned num3 = 0): kCapability::Context c c.data[0] = Kernel::Num (num1, num2) @@ -208,6 +217,13 @@ static void receiver_invoke (unsigned cmd, unsigned target, Kernel::Num protecte case Kernel::Receiver::CREATE_CALL_CAPABILITY & REQUEST_MASK: reply_cap (CAPTYPE_RECEIVER | (c->data[0].h ? Kernel::Receiver::CALL_ASYNC : Kernel::Receiver::CALL), protected_data, &((kObject *)protected_data.l)->refs) return + case Kernel::Receiver::GET_PROTECTED & REQUEST_MASK: + if !c->arg.valid () || c->arg->target != receiver: + dpanic (0, "wrong argument for get_protected") + reply_num (~0) + return + reply_num (c->arg->protected_data) + return case Kernel::Receiver::GET_REPLY_PROTECTED_DATA & REQUEST_MASK: reply_num (receiver->reply_protected_data.l, receiver->reply_protected_data.h, receiver->protected_only ? 1 : 0) return @@ -517,6 +533,8 @@ static void thread_invoke (unsigned cmd, unsigned target, Kernel::Num protected_ kPage *page = (kPage *)c->arg->protected_data.l reply_num (page->frame & ~0xc0000000) return + case Kernel::Thread::PRIV_REBOOT & REQUEST_MASK: + arch_reboot () case Kernel::Thread::PRIV_PANIC & REQUEST_MASK: panic (c->data[1].l, "panic requested by thread") reply_num (~0) diff --git a/iris.hhp b/iris.hhp index 394a728..05e02d1 100644 --- a/iris.hhp +++ b/iris.hhp @@ -129,6 +129,7 @@ namespace Kernel: struct Page struct Memory + void print_caps () unsigned alloc_slot () Cap alloc_cap () void free_slot (unsigned slot) @@ -256,6 +257,7 @@ namespace Kernel: CREATE_CAPABILITY CREATE_CALL_CAPABILITY CREATE_ASYNC_CALL_CAPABILITY + GET_PROTECTED GET_REPLY_PROTECTED_DATA SET_REPLY_PROTECTED_DATA GET_ALARM @@ -272,6 +274,8 @@ namespace Kernel: Cap create_capability (Num protected_data): icall (CAP_MASTER_DIRECT | CREATE_CAPABILITY, protected_data) return get_arg () + Num get_protected (Kernel::Cap target): + return ocall (target, CAP_MASTER_DIRECT | GET_PROTECTED) Num get_reply_protected_data (): return call (CAP_MASTER_DIRECT | GET_REPLY_PROTECTED_DATA) void set_reply_protected_data (Num data): @@ -309,6 +313,7 @@ namespace Kernel: // This is not an operation, but having this capability allows using the thread in Receiver::set_owner. SET_OWNER DBG_SEND + PRIV_REBOOT PRIV_PANIC // These get/set_info are not arch-specific. enum info_type: @@ -478,6 +483,8 @@ namespace Kernel: return get_arg () inline void dbg_send (unsigned code, unsigned bits = 32): my_thread.call (CAP_MASTER_DIRECT | Thread::DBG_SEND, Num (code, bits)) + inline void reboot (): + my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_REBOOT) inline void panic (unsigned code): my_thread.call (CAP_MASTER_DIRECT | Thread::PRIV_PANIC, code) diff --git a/kernel.hhp b/kernel.hhp index 8cdaa71..cbe9b92 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -263,6 +263,7 @@ void kMemory_arch_unmap (kMemory *mem, kPage *page, unsigned address) kPage *kMemory_arch_get_mapping (kMemory *mem, unsigned address, bool *readonly) void kPage_arch_update_mapping (kPage *page) void arch_register_interrupt (unsigned num, kReceiverP r) +void arch_reboot () bool kMemory::map (kPage *page, unsigned address, bool readonly = false): return kMemory_arch_map (this, page, address, readonly) diff --git a/mips/arch.ccp b/mips/arch.ccp index 22b4f13..a4ef20f 100644 --- a/mips/arch.ccp +++ b/mips/arch.ccp @@ -289,3 +289,15 @@ void arch_register_interrupt (unsigned num, kReceiver *r): intc_unmask_irq (num) else: intc_mask_irq (num) + +void arch_reboot (): + // Wait for serial port to be done. + while !(UART0_LSR & UARTLSR_TEMT): + // Reboot. + wdt_select_extalclk () + wdt_select_clk_div1 () + wdt_set_data (1) + wdt_set_count (0) + wdt_start () + // Wait for wdt to trigger reboot. + while true: diff --git a/mips/nanonote/Makefile.arch b/mips/nanonote/Makefile.arch index 9e90784..5a5d7c2 100644 --- a/mips/nanonote/Makefile.arch +++ b/mips/nanonote/Makefile.arch @@ -17,7 +17,7 @@ load = 0x80000000 -ARCH_CXXFLAGS = -DNUM_THREADS=2 +ARCH_CXXFLAGS = -DNUM_THREADS=4 ARCH_CPPFLAGS = -I. -Imips -Imips/nanonote -Wa,-mips32 -DNANONOTE -DUSE_SERIAL CROSS = mipsel-linux-gnu- OBJDUMP = $(CROSS)objdump @@ -28,7 +28,7 @@ LDFLAGS = --omagic -Ttext $(load) arch_iris_sources = mips/interrupts.cc mips/arch.cc boot_sources = mips/init.cc mips/nanonote/board.cc arch_headers = mips/arch.hh mips/nanonote/jz4740.hh mips/nanonote/board.hh -boot_threads = init udc +boot_threads = init udc nanonote-gpio buzzer test: iris.raw nanonote-boot ./nanonote-boot iris.raw 0xa$(shell /bin/sh -c '$(OBJDUMP) -t iris.elf | grep __start$$ | cut -b2-8') @@ -50,7 +50,7 @@ mips/entry.o: $(boot_threads) mips/init.o: TARGET_FLAGS = -I/usr/include $(boot_threads): TARGET_FLAGS = -I. $(boot_threads): LDFLAGS = -EL -$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): boot-programs/devices.hh boot-programs/init.hh +$(addprefix boot-programs/,$(addsuffix .cc,$(boot_threads))): boot-programs/devices.hh lcd: boot-programs/charset.data boot-programs/charset.data: boot-programs/charset @@ -63,4 +63,4 @@ boot-programs/charset.data: boot-programs/charset iris.elf: mips/entry.o $(subst .cc,.o,$(iris_sources)) mips/nanonote/threadlist.o mips/boot.o $(subst .cc,.o,$(boot_sources)) $(LD) $(LDFLAGS) $^ -o $@ -ARCH_CLEAN_FILES = $(boot_sources) $(boot_threads) $(arch_headers) boot_programs/init.hh boot_programs/devices.hh mips/*.o mips/nanonote/*.o boot-programs/charset.data iris.elf iris.raw mips/nanonote/sdram-setup.elf mips/nanonote/sdram-setup.raw +ARCH_CLEAN_FILES = $(boot_sources) $(boot_threads) $(arch_headers) boot_programs/devices.hh mips/*.o mips/nanonote/*.o boot-programs/charset.data iris.elf iris.raw mips/nanonote/sdram-setup.elf mips/nanonote/sdram-setup.raw diff --git a/mips/nanonote/board.ccp b/mips/nanonote/board.ccp index 772a166..ce27307 100644 --- a/mips/nanonote/board.ccp +++ b/mips/nanonote/board.ccp @@ -29,6 +29,7 @@ void board_init (): gpio_as_aic () gpio_as_lcd_16bit () gpio_as_msc () + setup_sdram () // Set up keyboard: this breaks uart receive. gpio_as_gpio (3, 0x05fc0000) tcu_stop_counter (0) diff --git a/mips/nanonote/jz4740.hhp b/mips/nanonote/jz4740.hhp index c0565e8..a538a6e 100644 --- a/mips/nanonote/jz4740.hhp +++ b/mips/nanonote/jz4740.hhp @@ -117,7 +117,7 @@ static void __map_io (unsigned physical, unsigned mapping): #define map_intc() do { __map_io (INTC_PHYSICAL, INTC_BASE); } while (0) #define map_tcu() do { __map_io (TCU_PHYSICAL, TCU_BASE); } while (0) #define map_wdt() do { __map_io (WDT_PHYSICAL, WDT_BASE); } while (0) -#define map_rtc() do { __map_io (RTC_PHYSICAL, RTC_BASE); } while (0) +#define map_rtc() do { __map_io (RTC_PHYSICAL, RTC_BASE); } while (1) #define map_gpio() do { __map_io (GPIO_PHYSICAL, GPIO_BASE); } while (0) #define map_aic() do { __map_io (AIC_PHYSICAL, AIC_BASE); } while (0) #define map_uart0() do { __map_io (UART0_PHYSICAL, UART0_BASE); } while (0) @@ -2322,7 +2322,7 @@ static void gpio_as_interrupt (unsigned p, unsigned pins, bool high, bool level) if high: GPIO_PXDIRS (p) = pins else: - GPIO_PXDIRS (p) = pins + GPIO_PXDIRC (p) = pins GPIO_PXFLGC (p) = pins static void gpio_set (unsigned p, unsigned pins): @@ -3577,4 +3577,103 @@ static void cim_enable_nongated_clock_mode (): +static void setup_sdram (): + // SDRAM BANK Number: 1, 2 + unsigned CONFIG_NR_DRAM_BANKS = 1 + // CAS latency: 2 or 3 + unsigned SDRAM_CASL = 3 + // SDRAM Timings, unit: ns + // RAS# Active Time + unsigned SDRAM_TRAS = 45 + // RAS# to CAS# Delay + unsigned SDRAM_RCD = 20 + // RAS# Precharge Time + unsigned SDRAM_TPC = 20 + // Write Latency Time + unsigned SDRAM_TRWL = 7 + // Refresh period: 4096 refresh cycles/64ms + unsigned SDRAM_TREF = 15625 + unsigned dmcr0, dmcr, sdmode, tmp, cpu_clk, mem_clk, ns + unsigned cas_latency_sdmr[2] = { EMC_SDMR_CAS_2, EMC_SDMR_CAS_3 } + unsigned cas_latency_dmcr[2] = { 1 << EMC_DMCR_TCL_BIT, 2 << EMC_DMCR_TCL_BIT } + int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32} + + cpu_clk = 225000000 + gpio_as_sdram_32bit () + unsigned SDRAM_BW16 = 0 + unsigned SDRAM_BANK4 = 1 + unsigned SDRAM_ROW = 13 + unsigned SDRAM_COL = 9 + + mem_clk = cpu_clk * div[cpm_get_cdiv()] / div[cpm_get_mdiv()] + EMC_BCR = 0 + EMC_RTCSR = 0 + unsigned SDRAM_ROW0 = 11 + unsigned SDRAM_COL0 = 8 + unsigned SDRAM_BANK40 = 0 + dmcr0 = ((SDRAM_ROW0-11)< 11: + tmp = 11 + dmcr |= ((tmp-4) << EMC_DMCR_TRAS_BIT) + tmp = SDRAM_RCD/ns + if tmp > 3: + tmp = 3 + dmcr |= (tmp << EMC_DMCR_RCD_BIT) + tmp = SDRAM_TPC/ns + if tmp > 7: + tmp = 7 + dmcr |= (tmp << EMC_DMCR_TPC_BIT) + tmp = SDRAM_TRWL/ns + if tmp > 3: + tmp = 3 + dmcr |= (tmp << EMC_DMCR_TRWL_BIT) + tmp = (SDRAM_TRAS + SDRAM_TPC)/ns + if tmp > 14: + tmp = 14 + dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT) + + // SDRAM mode value + sdmode = EMC_SDMR_BT_SEQ | EMC_SDMR_OM_NORMAL | EMC_SDMR_BL_4 | cas_latency_sdmr[((SDRAM_CASL == 3) ? 1 : 0)]; + + // Stage 1. Precharge all banks by writing SDMR with DMCR.MRSET=0 + EMC_DMCR = dmcr + REG8(EMC_SDMR0|sdmode) = 0 + + // Wait for precharge, > 200us + tmp = (cpu_clk / 1000000) * 1000 + volatile unsigned t = tmp + while t--: + + // Stage 2. Enable auto-refresh + EMC_DMCR = dmcr | EMC_DMCR_RFSH + + tmp = SDRAM_TREF/ns + tmp = tmp/64 + 1 + if tmp > 0xff: + tmp = 0xff + EMC_RTCOR = tmp + EMC_RTCNT = 0 + // Divisor is 64, CKO/64 + EMC_RTCSR = EMC_RTCSR_CKS_64 + + // Wait for number of auto-refresh cycles + tmp = (cpu_clk / 1000000) * 1000 + t = tmp + while t--: + + // Stage 3. Mode Register Set + EMC_DMCR = dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET + REG8(EMC_SDMR0|sdmode) = 0 + + // Set back to basic DMCR value + EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET + + #endif diff --git a/mips/nanonote/nanonote-boot.ccp b/mips/nanonote/nanonote-boot.ccp index fa3b7cf..da13740 100644 --- a/mips/nanonote/nanonote-boot.ccp +++ b/mips/nanonote/nanonote-boot.ccp @@ -132,6 +132,13 @@ nanonote::nanonote (unsigned skip): if !find_device (skip): std::cerr << "unable to find NanoNote device.\n"; throw "unable to find NanoNote device"; + // Get info will reset the device if it has already booted into Iris. + get_cpu_info () + usb_close (handle) + sleep (1) + if !find_device (skip): + std::cerr << "unable to find NanoNote device again.\n"; + throw "unable to find NanoNote device again"; void nanonote::get_cpu_info (): char buffer[8] @@ -141,14 +148,12 @@ void nanonote::get_cpu_info (): cpu_info = std::string (buffer, 8) void nanonote::request (requests r, unsigned data): - std::cerr << "requesting " << r << " (data = " << std::hex << data << ")" << std::endl if usb_control_msg (handle, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, r, (data >> 16) & 0xffff, data & 0xffff, NULL, 0, timeout) < 0: std::cerr << "unable to send control message to NanoNote: " << usb_strerror () << ".\n" throw "unable to send control message to NanoNote" void nanonote::send_file (unsigned address, unsigned size, char const *data): request (VR_SET_DATA_ADDRESS, address) - //request (VR_SET_DATA_LENGTH, size) char const *ptr = data while ptr - data < size: int ret = usb_bulk_write (handle, out_ep, ptr, size - (ptr - data), timeout) @@ -158,20 +163,12 @@ void nanonote::send_file (unsigned address, unsigned size, char const *data): ptr += ret void nanonote::boot (std::string const &data, unsigned load, unsigned start): - get_cpu_info () - std::cerr << "info: " << cpu_info << std::endl send_file (stage1_load, stage1_size, stage1) request (VR_PROGRAM_START1, stage1_start) usleep (100) send_file (load, data.size (), data.data ()) request (VR_FLUSH_CACHES) request (VR_PROGRAM_START2, start) - sleep (1) - get_cpu_info () - std::cerr << "info: "; - for unsigned i = 0; i < cpu_info.size (); ++i: - std::cerr << std::setfill ('0') << std::setw (2) << std::hex << (cpu_info[i] & 0xff); - std::cerr << std::endl int main (int argc, char **argv): if argc != 3: diff --git a/mips/nanonote/sdram-setup.ccp b/mips/nanonote/sdram-setup.ccp index e24723f..177cc4b 100644 --- a/mips/nanonote/sdram-setup.ccp +++ b/mips/nanonote/sdram-setup.ccp @@ -20,15 +20,6 @@ #define __KERNEL #include "jz4740.hh" -#define CONFIG_NR_DRAM_BANKS 1 // SDRAM BANK Number: 1, 2 -#define SDRAM_CASL 3 // CAS latency: 2 or 3 -// SDRAM Timings, unit: ns -#define SDRAM_TRAS 45 // RAS# Active Time -#define SDRAM_RCD 20 // RAS# to CAS# Delay -#define SDRAM_TPC 20 // RAS# Precharge Time -#define SDRAM_TRWL 7 // Write Latency Time -#define SDRAM_TREF 15625 // Refresh period: 4096 refresh cycles/64ms - asm volatile (".set noreorder\n" "\t.globl __start\n" "\t.text\n" @@ -51,102 +42,5 @@ extern "C": void start_cpp () void start_cpp (): - unsigned dmcr0, dmcr, sdmode, tmp, cpu_clk, mem_clk, ns - unsigned cas_latency_sdmr[2] = { EMC_SDMR_CAS_2, EMC_SDMR_CAS_3 } - unsigned cas_latency_dmcr[2] = { 1 << EMC_DMCR_TCL_BIT, 2 << EMC_DMCR_TCL_BIT } - int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32} - - cpu_clk = 225000000 - gpio_as_sdram_32bit () - unsigned SDRAM_BW16 = 0 - unsigned SDRAM_BANK4 = 1 - unsigned SDRAM_ROW = 13 - unsigned SDRAM_COL = 9 - - mem_clk = cpu_clk * div[cpm_get_cdiv()] / div[cpm_get_mdiv()] - EMC_BCR = 0 - EMC_RTCSR = 0 - #define SDRAM_ROW0 11 - #define SDRAM_COL0 8 - #define SDRAM_BANK40 0 - dmcr0 = ((SDRAM_ROW0-11)< 11: - tmp = 11 - dmcr |= ((tmp-4) << EMC_DMCR_TRAS_BIT) - tmp = SDRAM_RCD/ns - if tmp > 3: - tmp = 3 - dmcr |= (tmp << EMC_DMCR_RCD_BIT) - tmp = SDRAM_TPC/ns - if tmp > 7: - tmp = 7 - dmcr |= (tmp << EMC_DMCR_TPC_BIT) - tmp = SDRAM_TRWL/ns - if tmp > 3: - tmp = 3 - dmcr |= (tmp << EMC_DMCR_TRWL_BIT) - tmp = (SDRAM_TRAS + SDRAM_TPC)/ns - if tmp > 14: - tmp = 14 - dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT) - - // SDRAM mode value - sdmode = EMC_SDMR_BT_SEQ | EMC_SDMR_OM_NORMAL | EMC_SDMR_BL_4 | cas_latency_sdmr[((SDRAM_CASL == 3) ? 1 : 0)]; - - // Stage 1. Precharge all banks by writing SDMR with DMCR.MRSET=0 - EMC_DMCR = dmcr - REG8(EMC_SDMR0|sdmode) = 0 - - // Wait for precharge, > 200us - tmp = (cpu_clk / 1000000) * 1000 - volatile unsigned t = tmp - while t--: - - // Stage 2. Enable auto-refresh - EMC_DMCR = dmcr | EMC_DMCR_RFSH - - tmp = SDRAM_TREF/ns - tmp = tmp/64 + 1 - if tmp > 0xff: - tmp = 0xff - EMC_RTCOR = tmp - EMC_RTCNT = 0 - // Divisor is 64, CKO/64 - EMC_RTCSR = EMC_RTCSR_CKS_64 - - // Wait for number of auto-refresh cycles - tmp = (cpu_clk / 1000000) * 1000 - t = tmp - while t--: - - // Stage 3. Mode Register Set - EMC_DMCR = dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET - REG8(EMC_SDMR0|sdmode) = 0 - - // Set back to basic DMCR value - EMC_DMCR = dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET - + setup_sdram () // everything is ok now: return to boot loader to load stage 2. - - pll_init () - cpm_start_all () - gpio_as_uart0 () - UART0_IER = 0 - UART0_FCR = 0 - UART0_MCR = 0 - UART0_SIRCR = 0 - UART0_UMR = 0 - UART0_UACR = 0 - UART0_LCR = UARTLCR_WLEN_8 | UARTLCR_STOP1 | UARTLCR_DLAB - unsigned uart_div = 3000000 / 16 / 9600 - UART0_DLHR = uart_div >> 8 - UART0_DLLR = uart_div - UART0_LCR = UARTLCR_WLEN_8 | UARTLCR_STOP1 - UART0_FCR = UARTFCR_UUE | UARTFCR_FE | UARTFCR_RFLS | UARTFCR_TFLS diff --git a/mips/nanonote/threadlist.S b/mips/nanonote/threadlist.S index 66deb6e..4187f9a 100644 --- a/mips/nanonote/threadlist.S +++ b/mips/nanonote/threadlist.S @@ -27,7 +27,15 @@ thread0: thread1: .incbin "udc" + .balign 0x1000 thread2: + .incbin "nanonote-gpio" + + .balign 0x1000 +thread3: + .incbin "buzzer" + +thread4: // Everything from here may be freed after kernel initialization. init_start: @@ -36,3 +44,5 @@ thread_start: .word thread0 .word thread1 .word thread2 + .word thread3 + .word thread4 diff --git a/panic.ccp b/panic.ccp index 81196d6..67864fc 100644 --- a/panic.ccp +++ b/panic.ccp @@ -77,6 +77,9 @@ void panic_impl (unsigned n, unsigned line, char const *name, char const *messag dbg_log_num (n) dbg_log_char ('\n') // If no log capability is registered, the machine just hangs. + #ifdef USE_SERIAL + arch_reboot () + #endif #endif #ifndef NDEBUG void dbg_send (unsigned num, unsigned bits): diff --git a/plan b/plan index 5e9608e..0f67c56 100644 --- a/plan +++ b/plan @@ -1,2 +1,28 @@ caps zonder size limit? invoke ipc: try sync; try receiver memory; try caller memory; fail. + +memories map: + +top +- lcd +- keyboard +- sound +- led +- udc +- battery +- beeper +- msc +- nand +- filesystem +- network +- top session manager +- - user session +- - - program container +- - - - driver emulation +- - - - driver emulation +- - - - program +- - - program container +- - - - driver emulation +- - - - program +- - user session +...