diff options
author | Stephane Carrez <stcarrez@nerim.fr> | 2002-03-07 19:12:44 +0000 |
---|---|---|
committer | Stephane Carrez <stcarrez@nerim.fr> | 2002-03-07 19:12:44 +0000 |
commit | 827ec39a5a8af8821006d93978623dc1ababdac1 (patch) | |
tree | 7f3e2c7e8cad430e5fa9bccc996f55a8d1f5d942 /sim | |
parent | 5abb9efa086f5bd9eeacf3911d0b528cc522b870 (diff) | |
download | fsf-binutils-gdb-827ec39a5a8af8821006d93978623dc1ababdac1.zip fsf-binutils-gdb-827ec39a5a8af8821006d93978623dc1ababdac1.tar.gz fsf-binutils-gdb-827ec39a5a8af8821006d93978623dc1ababdac1.tar.bz2 |
* interp.c (sim_hw_configure): Save the HW cpu pointer in the
cpu struct.
(sim_hw_configure): Connect the capture input/output events.
* sim-main.h (_sim_cpu): New member hw_cpu.
(m68hc11cpu_set_oscillator): Declare.
(m68hc11cpu_clear_oscillator): Declare.
(m68hc11cpu_set_port): Declare.
* dv-m68hc11.c (m68hc11_options): New for oscillator commands.
(m68hc11cpu_ports): New input ports and output ports to reflect
the HC11 IOs.
(m68hc11_delete): Cleanup any running oscillator.
(attach_m68hc11_regs): Create the input oscillators.
(make_oscillator): New function.
(find_oscillator): New function.
(oscillator_handler): New function.
(reset_oscillators): New function.
(m68hc11cpu_port_event): Handle the new input ports.
(m68hc11cpu_set_oscillator): New function.
(m68hc11cpu_clear_oscillator): New function.
(get_frequency): New function.
(m68hc11_option_handler): New function.
(m68hc11cpu_set_port): New function.
(m68hc11cpu_io_write): Post the port output events.
* dv-m68hc11spi.c (set_bit_port): Use m68hc11cpu_set_port to set
the output port value.
* dv-m68hc11tim.c (m68hc11tim_port_event): Handle CAPTURE event
by latching the TCNT value in the register.
Diffstat (limited to 'sim')
-rw-r--r-- | sim/m68hc11/ChangeLog | 30 | ||||
-rw-r--r-- | sim/m68hc11/dv-m68hc11.c | 498 | ||||
-rw-r--r-- | sim/m68hc11/dv-m68hc11spi.c | 16 | ||||
-rw-r--r-- | sim/m68hc11/dv-m68hc11tim.c | 36 | ||||
-rw-r--r-- | sim/m68hc11/interp.c | 4 | ||||
-rw-r--r-- | sim/m68hc11/sim-main.h | 11 |
6 files changed, 579 insertions, 16 deletions
diff --git a/sim/m68hc11/ChangeLog b/sim/m68hc11/ChangeLog index 7c2f7a1..eec5cbc 100644 --- a/sim/m68hc11/ChangeLog +++ b/sim/m68hc11/ChangeLog @@ -1,5 +1,35 @@ 2002-03-07 Stephane Carrez <Stephane.Carrez@worldnet.fr> + * interp.c (sim_hw_configure): Save the HW cpu pointer in the + cpu struct. + (sim_hw_configure): Connect the capture input/output events. + * sim-main.h (_sim_cpu): New member hw_cpu. + (m68hc11cpu_set_oscillator): Declare. + (m68hc11cpu_clear_oscillator): Declare. + (m68hc11cpu_set_port): Declare. + * dv-m68hc11.c (m68hc11_options): New for oscillator commands. + (m68hc11cpu_ports): New input ports and output ports to reflect + the HC11 IOs. + (m68hc11_delete): Cleanup any running oscillator. + (attach_m68hc11_regs): Create the input oscillators. + (make_oscillator): New function. + (find_oscillator): New function. + (oscillator_handler): New function. + (reset_oscillators): New function. + (m68hc11cpu_port_event): Handle the new input ports. + (m68hc11cpu_set_oscillator): New function. + (m68hc11cpu_clear_oscillator): New function. + (get_frequency): New function. + (m68hc11_option_handler): New function. + (m68hc11cpu_set_port): New function. + (m68hc11cpu_io_write): Post the port output events. + * dv-m68hc11spi.c (set_bit_port): Use m68hc11cpu_set_port to set + the output port value. + * dv-m68hc11tim.c (m68hc11tim_port_event): Handle CAPTURE event + by latching the TCNT value in the register. + +2002-03-07 Stephane Carrez <Stephane.Carrez@worldnet.fr> + * sim-main.h (cpu_frame, cpu_frame_list): Remove. (cpu_frame_reg, cpu_print_frame): Remove. (cpu_m68hc11_push_uint8, cpu_m68hc11_pop_uint8): Cleanup. diff --git a/sim/m68hc11/dv-m68hc11.c b/sim/m68hc11/dv-m68hc11.c index f300297..5fc25a9 100644 --- a/sim/m68hc11/dv-m68hc11.c +++ b/sim/m68hc11/dv-m68hc11.c @@ -1,5 +1,5 @@ /* dv-m68hc11.c -- CPU 68HC11&68HC12 as a device. - Copyright (C) 1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Written by Stephane Carrez (stcarrez@worldnet.fr) (From a driver model Contributed by Cygnus Solutions.) @@ -21,7 +21,10 @@ #include "sim-main.h" +#include "sim-hw.h" #include "hw-main.h" +#include "sim-options.h" +#include <limits.h> /* DEVICE @@ -62,11 +65,27 @@ Deliver a non-maskable interrupt to the processor. + set-port-a (input) + set-port-c (input) + set-pord-d (input) + + Allow an external device to set the value of port A, C or D inputs. + + cpu-reset (output) Event generated after the CPU performs a reset. + port-a (output) + port-b (output) + port-c (output) + port-d (output) + + Event generated when the value of the output port A, B, C or D + changes. + + BUGS When delivering an interrupt, this code assumes that there is only @@ -74,8 +93,47 @@ */ +enum +{ + OPTION_OSC_SET = OPTION_START, + OPTION_OSC_CLEAR, + OPTION_OSC_INFO +}; + +static DECLARE_OPTION_HANDLER (m68hc11_option_handler); + +static const OPTION m68hc11_options[] = +{ + { {"osc-set", required_argument, NULL, OPTION_OSC_SET }, + '\0', "BIT,FREQ", "Set the oscillator on input port BIT", + m68hc11_option_handler }, + { {"osc-clear", required_argument, NULL, OPTION_OSC_CLEAR }, + '\0', "BIT", "Clear oscillator on input port BIT", + m68hc11_option_handler }, + { {"osc-info", no_argument, NULL, OPTION_OSC_INFO }, + '\0', NULL, "Print information about current input oscillators", + m68hc11_option_handler }, + + { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } +}; +struct input_osc +{ + signed64 on_time; + signed64 off_time; + signed64 repeat; + struct hw_event *event; + const char *name; + uint8 mask; + uint8 value; + uint16 addr; +}; +#define NR_PORT_A_OSC (4) +#define NR_PORT_B_OSC (0) +#define NR_PORT_C_OSC (8) +#define NR_PORT_D_OSC (6) +#define NR_OSC (NR_PORT_A_OSC + NR_PORT_B_OSC + NR_PORT_C_OSC + NR_PORT_D_OSC) struct m68hc11cpu { /* Pending interrupts for delivery by event handler. */ int pending_reset; @@ -85,6 +143,8 @@ struct m68hc11cpu { unsigned_word attach_address; int attach_size; int attach_space; + int last_oscillator; + struct input_osc oscillators[NR_OSC]; }; @@ -95,7 +155,15 @@ enum { RESET_PORT, NMI_PORT, IRQ_PORT, - CPU_RESET_PORT + CPU_RESET_PORT, + SET_PORT_A, + SET_PORT_C, + SET_PORT_D, + PORT_A, + PORT_B, + PORT_C, + PORT_D, + CAPTURE }; @@ -106,9 +174,22 @@ static const struct hw_port_descriptor m68hc11cpu_ports[] = { { "nmi", NMI_PORT, 0, input_port, }, { "irq", IRQ_PORT, 0, input_port, }, + { "set-port-a", SET_PORT_A, 0, input_port, }, + { "set-port-c", SET_PORT_C, 0, input_port, }, + { "set-port-d", SET_PORT_D, 0, input_port, }, + /* Events generated for connection to other devices. */ { "cpu-reset", CPU_RESET_PORT, 0, output_port, }, + /* Events generated when the corresponding port is + changed by the program. */ + { "port-a", PORT_A, 0, output_port, }, + { "port-b", PORT_B, 0, output_port, }, + { "port-c", PORT_C, 0, output_port, }, + { "port-d", PORT_D, 0, output_port, }, + + { "capture", CAPTURE, 0, output_port, }, + { NULL, }, }; @@ -121,6 +202,11 @@ static hw_ioctl_method m68hc11_ioctl; static hw_port_event_method m68hc11cpu_port_event; +static void make_oscillator (struct m68hc11cpu *controller, + const char *id, uint16 addr, uint8 mask); +static struct input_osc *find_oscillator (struct m68hc11cpu *controller, + const char *id); +static void reset_oscillators (struct hw *me); static void dv_m6811_attach_address_callback (struct hw *me, @@ -180,6 +266,7 @@ m68hc11_delete (struct hw* me) controller = hw_data (me); + reset_oscillators (me); hw_detach_address (me, M6811_IO_LEVEL, controller->attach_space, controller->attach_address, @@ -242,6 +329,37 @@ attach_m68hc11_regs (struct hw *me, cpu->cpu_mode = 0; else cpu->cpu_mode = M6811_MDA; + + controller->last_oscillator = 0; + + /* Create oscillators for input port A. */ + make_oscillator (controller, "A7", M6811_PORTA, 0x80); + make_oscillator (controller, "A2", M6811_PORTA, 0x04); + make_oscillator (controller, "A1", M6811_PORTA, 0x02); + make_oscillator (controller, "A0", M6811_PORTA, 0x01); + + /* port B is output only. */ + + /* Create oscillators for input port C. */ + make_oscillator (controller, "C0", M6811_PORTC, 0x01); + make_oscillator (controller, "C1", M6811_PORTC, 0x02); + make_oscillator (controller, "C2", M6811_PORTC, 0x04); + make_oscillator (controller, "C3", M6811_PORTC, 0x08); + make_oscillator (controller, "C4", M6811_PORTC, 0x10); + make_oscillator (controller, "C5", M6811_PORTC, 0x20); + make_oscillator (controller, "C6", M6811_PORTC, 0x40); + make_oscillator (controller, "C7", M6811_PORTC, 0x80); + + /* Create oscillators for input port D. */ + make_oscillator (controller, "D0", M6811_PORTD, 0x01); + make_oscillator (controller, "D1", M6811_PORTD, 0x02); + make_oscillator (controller, "D2", M6811_PORTD, 0x04); + make_oscillator (controller, "D3", M6811_PORTD, 0x08); + make_oscillator (controller, "D4", M6811_PORTD, 0x10); + make_oscillator (controller, "D5", M6811_PORTD, 0x20); + + /* Add oscillator commands. */ + sim_add_option_table (sd, 0, m68hc11_options); } static void @@ -279,8 +397,87 @@ deliver_m68hc11cpu_interrupt (struct hw *me, void *data) { } +static void +make_oscillator (struct m68hc11cpu *controller, const char *name, + uint16 addr, uint8 mask) +{ + struct input_osc *osc; + + if (controller->last_oscillator >= NR_OSC) + hw_abort (0, "Too many oscillators"); + + osc = &controller->oscillators[controller->last_oscillator]; + osc->name = name; + osc->addr = addr; + osc->mask = mask; + controller->last_oscillator++; +} + +/* Find the oscillator given the input port name. */ +static struct input_osc * +find_oscillator (struct m68hc11cpu *controller, const char *name) +{ + int i; + + for (i = 0; i < controller->last_oscillator; i++) + if (strcasecmp (controller->oscillators[i].name, name) == 0) + return &controller->oscillators[i]; + + return 0; +} static void +oscillator_handler (struct hw *me, void *data) +{ + struct input_osc *osc = (struct input_osc*) data; + SIM_DESC sd; + sim_cpu *cpu; + signed64 dt; + uint8 val; + + sd = hw_system (me); + cpu = STATE_CPU (sd, 0); + + /* Change the input bit. */ + osc->value ^= osc->mask; + val = cpu->ios[osc->addr] & ~osc->mask; + val |= osc->value; + m68hc11cpu_set_port (me, cpu, osc->addr, val); + + /* Setup event to toggle the bit. */ + if (osc->value) + dt = osc->on_time; + else + dt = osc->off_time; + + if (dt && --osc->repeat >= 0) + { + sim_events *events = STATE_EVENTS (sd); + + dt += events->nr_ticks_to_process; + osc->event = hw_event_queue_schedule (me, dt, oscillator_handler, osc); + } + else + osc->event = 0; +} + +static void +reset_oscillators (struct hw *me) +{ + struct m68hc11cpu *controller = hw_data (me); + int i; + + for (i = 0; i < controller->last_oscillator; i++) + { + if (controller->oscillators[i].event) + { + hw_event_queue_deschedule (me, controller->oscillators[i].event); + controller->oscillators[i].event = 0; + } + } +} + +static void m68hc11cpu_port_event (struct hw *me, int my_port, struct hw *source, @@ -304,6 +501,7 @@ m68hc11cpu_port_event (struct hw *me, - Restart the cpu for the reset (get the CPU mode from the CONFIG register that gets initialized by EEPROM device). */ cpu_reset (cpu); + reset_oscillators (me); hw_port_event (me, CPU_RESET_PORT, 1); cpu_restart (cpu); break; @@ -321,7 +519,19 @@ m68hc11cpu_port_event (struct hw *me, controller->pending_level = level; HW_TRACE ((me, "port-in level=%d", level)); break; + + case SET_PORT_A: + m68hc11cpu_set_port (me, cpu, M6811_PORTA, level); + break; + case SET_PORT_C: + m68hc11cpu_set_port (me, cpu, M6811_PORTC, level); + break; + + case SET_PORT_D: + m68hc11cpu_set_port (me, cpu, M6811_PORTD, level); + break; + default: hw_abort (me, "bad switch"); break; @@ -411,6 +621,180 @@ m68hc11_ioctl (struct hw *me, return 0; } +/* Setup an oscillator on an input port. + + TON represents the time in seconds that the input port should be set to 1. + TOFF is the time in seconds for the input port to be set to 0. + + The oscillator frequency is therefore 1 / (ton + toff). + + REPEAT indicates the number of 1 <-> 0 transitions until the oscillator + stops. */ +int +m68hc11cpu_set_oscillator (SIM_DESC sd, const char *port, + double ton, double toff, signed64 repeat) +{ + sim_cpu *cpu; + struct input_osc *osc; + double f; + + cpu = STATE_CPU (sd, 0); + + /* Find oscillator that corresponds to the input port. */ + osc = find_oscillator (hw_data (cpu->hw_cpu), port); + if (osc == 0) + return -1; + + /* Compute the ON time in cpu cycles. */ + f = (double) (cpu->cpu_frequency) * ton; + osc->on_time = (signed64) (f / 4.0); + if (osc->on_time < 1) + osc->on_time = 1; + + /* Compute the OFF time in cpu cycles. */ + f = (double) (cpu->cpu_frequency) * toff; + osc->off_time = (signed64) (f / 4.0); + if (osc->off_time < 1) + osc->off_time = 1; + + osc->repeat = repeat; + if (osc->event) + hw_event_queue_deschedule (cpu->hw_cpu, osc->event); + + osc->event = hw_event_queue_schedule (cpu->hw_cpu, + osc->value ? osc->on_time + : osc->off_time, + oscillator_handler, osc); + return 0; +} + +/* Clear the oscillator. */ +int +m68hc11cpu_clear_oscillator (SIM_DESC sd, const char *port) +{ + sim_cpu *cpu; + struct input_osc *osc; + + cpu = STATE_CPU (sd, 0); + osc = find_oscillator (hw_data (cpu->hw_cpu), port); + if (osc == 0) + return -1; + + if (osc->event) + hw_event_queue_deschedule (cpu->hw_cpu, osc->event); + osc->event = 0; + osc->repeat = 0; + return 0; +} + +static int +get_frequency (const char *s, double *f) +{ + char *p; + + *f = strtod (s, &p); + if (s == p) + return -1; + + if (*p) + { + if (strcasecmp (p, "khz") == 0) + *f = *f * 1000.0; + else if (strcasecmp (p, "mhz") == 0) + *f = *f * 1000000.0; + else if (strcasecmp (p, "hz") != 0) + return -1; + } + return 0; +} + +static SIM_RC +m68hc11_option_handler (SIM_DESC sd, sim_cpu *cpu, + int opt, char *arg, int is_command) +{ + struct m68hc11cpu *controller; + double f; + char *p; + int i; + int title_printed = 0; + + if (cpu == 0) + cpu = STATE_CPU (sd, 0); + + controller = hw_data (cpu->hw_cpu); + switch (opt) + { + case OPTION_OSC_SET: + p = strchr (arg, ','); + if (p) + *p++ = 0; + + if (p == 0) + sim_io_eprintf (sd, "No frequency specified\n"); + else if (get_frequency (p, &f) < 0 || f < 1.0e-8) + sim_io_eprintf (sd, "Invalid frequency: '%s'\n", p); + else if (m68hc11cpu_set_oscillator (sd, arg, + 1.0 / (f * 2.0), + 1.0 / (f * 2.0), LONG_MAX)) + sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg); + break; + + case OPTION_OSC_CLEAR: + if (m68hc11cpu_clear_oscillator (sd, arg) != 0) + sim_io_eprintf (sd, "Invalid input port: '%s'\n", arg); + break; + + case OPTION_OSC_INFO: + for (i = 0; i < controller->last_oscillator; i++) + { + signed64 t; + struct input_osc *osc; + + osc = &controller->oscillators[i]; + if (osc->event) + { + double f; + int cur_value; + int next_value; + char freq[32]; + + if (title_printed == 0) + { + title_printed = 1; + sim_io_printf (sd, " PORT Frequency Current" + " Next Transition time\n"); + } + + f = (double) (osc->on_time + osc->off_time); + f = (double) (cpu->cpu_frequency / 4) / f; + t = hw_event_remain_time (cpu->hw_cpu, osc->event); + + if (f > 10000.0) + sprintf (freq, "%6.2f", f / 1000.0); + else + sprintf (freq, "%6.2f", f); + cur_value = osc->value ? 1 : 0; + next_value = osc->value ? 0 : 1; + if (f > 10000.0) + sim_io_printf (sd, " %4.4s %8.8s khz" + " %d %d %35.35s\n", + osc->name, freq, + cur_value, next_value, + cycle_to_string (cpu, t)); + else + sim_io_printf (sd, " %4.4s %8.8s hz " + " %d %d %35.35s\n", + osc->name, freq, + cur_value, next_value, + cycle_to_string (cpu, t)); + } + } + break; + } + + return SIM_RC_OK; +} + /* generic read/write */ static unsigned @@ -428,7 +812,7 @@ m68hc11cpu_io_read_buffer (struct hw *me, HW_TRACE ((me, "read 0x%08lx %d", (long) base, (int) nr_bytes)); - sd = hw_system (me); + sd = hw_system (me); cpu = STATE_CPU (sd, 0); /* Handle reads for the sub-devices. */ @@ -452,6 +836,110 @@ m68hc11cpu_io_read_buffer (struct hw *me, return byte; } +void +m68hc11cpu_set_port (struct hw *me, sim_cpu *cpu, + unsigned addr, uint8 val) +{ + uint8 mask; + uint8 delta; + int check_interrupts = 0; + int i; + + switch (addr) + { + case M6811_PORTA: + if (cpu->ios[M6811_PACTL] & M6811_DDRA7) + mask = 3; + else + mask = 0x83; + + val = val & mask; + val |= cpu->ios[M6811_PORTA] & ~mask; + delta = val ^ cpu->ios[M6811_PORTA]; + cpu->ios[M6811_PORTA] = val; + if (delta & 0x80) + { + /* Pulse accumulator is enabled. */ + if ((cpu->ios[M6811_PACTL] & M6811_PAEN) + && !(cpu->ios[M6811_PACTL] & M6811_PAMOD)) + { + int inc; + + /* Increment event counter according to rising/falling edge. */ + if (cpu->ios[M6811_PACTL] & M6811_PEDGE) + inc = (val & 0x80) ? 1 : 0; + else + inc = (val & 0x80) ? 0 : 1; + + cpu->ios[M6811_PACNT] += inc; + + /* Event counter overflowed. */ + if (inc && cpu->ios[M6811_PACNT] == 0) + { + cpu->ios[M6811_TFLG2] |= M6811_PAOVI; + check_interrupts = 1; + } + } + } + + /* Scan IC3, IC2 and IC1. Bit number is 3 - i. */ + for (i = 0; i < 3; i++) + { + uint8 mask = (1 << i); + + if (delta & mask) + { + uint8 edge; + int captured; + + edge = cpu->ios[M6811_TCTL2]; + edge = (edge >> (2 * i)) & 0x3; + switch (edge) + { + case 0: + captured = 0; + break; + case 1: + captured = (val & mask) != 0; + break; + case 2: + captured = (val & mask) == 0; + break; + default: + captured = 1; + break; + } + if (captured) + { + cpu->ios[M6811_TFLG1] |= (1 << i); + hw_port_event (me, CAPTURE, M6811_TIC1 + 3 - i); + check_interrupts = 1; + } + } + } + break; + + case M6811_PORTC: + mask = cpu->ios[M6811_DDRC]; + val = val & mask; + val |= cpu->ios[M6811_PORTC] & ~mask; + cpu->ios[M6811_PORTC] = val; + break; + + case M6811_PORTD: + mask = cpu->ios[M6811_DDRD]; + val = val & mask; + val |= cpu->ios[M6811_PORTD] & ~mask; + cpu->ios[M6811_PORTD] = val; + break; + + default: + break; + } + + if (check_interrupts) + interrupts_update_pending (&cpu->cpu_interrupts); +} static void m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu, @@ -460,15 +948,18 @@ m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu, switch (addr) { case M6811_PORTA: + hw_port_event (me, PORT_A, val); break; case M6811_PIOC: break; case M6811_PORTC: + hw_port_event (me, PORT_C, val); break; case M6811_PORTB: + hw_port_event (me, PORT_B, val); break; case M6811_PORTCL: @@ -478,6 +969,7 @@ m68hc11cpu_io_write (struct hw *me, sim_cpu *cpu, break; case M6811_PORTD: + hw_port_event (me, PORT_D, val); break; case M6811_DDRD: diff --git a/sim/m68hc11/dv-m68hc11spi.c b/sim/m68hc11/dv-m68hc11spi.c index d0bdfda..5f5e0bb 100644 --- a/sim/m68hc11/dv-m68hc11spi.c +++ b/sim/m68hc11/dv-m68hc11spi.c @@ -1,5 +1,5 @@ /* dv-m68hc11spi.c -- Simulation of the 68HC11 SPI - Copyright (C) 2000 Free Software Foundation, Inc. + Copyright (C) 2000, 2002 Free Software Foundation, Inc. Written by Stephane Carrez (stcarrez@worldnet.fr) (From a driver model Contributed by Cygnus Solutions.) @@ -192,14 +192,16 @@ m68hc11spi_port_event (struct hw *me, static void set_bit_port (struct hw *me, sim_cpu *cpu, int port, int mask, int value) { - /* TODO: Post an event to inform other devices that pin 'port' changes. - This has only a sense if we provide some device that is logically - connected to these pin ports (SCLK and MOSI) and that handles - the SPI protocol. */ + uint8 val; + if (value) - cpu->ios[port] |= mask; + val = cpu->ios[port] | mask; else - cpu->ios[port] &= ~mask; + val = cpu->ios[port] & ~mask; + + /* Set the new value and post an event to inform other devices + that pin 'port' changed. */ + m68hc11cpu_set_port (me, cpu, port, val); } diff --git a/sim/m68hc11/dv-m68hc11tim.c b/sim/m68hc11/dv-m68hc11tim.c index 144ae4b..9b0f338 100644 --- a/sim/m68hc11/dv-m68hc11tim.c +++ b/sim/m68hc11/dv-m68hc11tim.c @@ -1,5 +1,5 @@ /* dv-m68hc11tim.c -- Simulation of the 68HC11 timer devices. - Copyright (C) 1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc. Written by Stephane Carrez (stcarrez@worldnet.fr) (From a driver model Contributed by Cygnus Solutions.) @@ -50,6 +50,12 @@ Reset the timer device. This port must be connected to the cpu-reset output port. + capture (input) + + Input capture. This port must be connected to the input + captures. It latches the current TCNT free running counter + into one of the three input capture registers. + */ @@ -58,13 +64,15 @@ enum { - RESET_PORT + RESET_PORT, + CAPTURE }; static const struct hw_port_descriptor m68hc11tim_ports[] = { - { "reset", RESET_PORT, 0, input_port, }, + { "reset", RESET_PORT, 0, input_port, }, + { "capture", CAPTURE, 0, input_port, }, { NULL, }, }; @@ -137,7 +145,6 @@ m68hc11tim_finish (struct hw *me) } - /* An event arrives on an interrupt port. */ static void @@ -151,7 +158,8 @@ m68hc11tim_port_event (struct hw *me, struct m68hc11tim *controller; sim_cpu *cpu; unsigned8 val; - + unsigned16 tcnt; + controller = hw_data (me); sd = hw_system (me); cpu = STATE_CPU (sd, 0); @@ -197,6 +205,24 @@ m68hc11tim_port_event (struct hw *me, break; } + case CAPTURE: + tcnt = (uint16) ((cpu->cpu_absolute_cycle - controller->tcnt_adjust) + / controller->clock_prescaler); + switch (level) + { + case M6811_TIC1: + case M6811_TIC2: + case M6811_TIC3: + cpu->ios[level] = tcnt >> 8; + cpu->ios[level + 1] = tcnt; + break; + + default: + hw_abort (me, "Invalid event parameter %d", level); + break; + } + break; + default: hw_abort (me, "Event on unknown port %d", my_port); break; diff --git a/sim/m68hc11/interp.c b/sim/m68hc11/interp.c index cba7232..0cdf16a 100644 --- a/sim/m68hc11/interp.c +++ b/sim/m68hc11/interp.c @@ -208,6 +208,7 @@ sim_hw_configure (SIM_DESC sd) /* M68hc11 Timer configuration. */ sim_hw_parse (sd, "/m68hc11/m68hc11tim/reg 0x1b 0x5"); sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11tim"); + sim_hw_parse (sd, "/m68hc11 > capture capture /m68hc11/m68hc11tim"); } /* Create the SPI device. */ @@ -229,6 +230,7 @@ sim_hw_configure (SIM_DESC sd) sim_hw_parse (sd, "/m68hc11/m68hc11eepr/reg 0xb000 512"); sim_hw_parse (sd, "/m68hc11 > cpu-reset reset /m68hc11/m68hc11eepr"); } + cpu->hw_cpu = sim_hw_parse (sd, "/m68hc11"); } else { @@ -281,6 +283,8 @@ sim_hw_configure (SIM_DESC sd) sim_hw_parse (sd, "/m68hc12/m68hc12eepr/reg 0x0800 2048"); sim_hw_parse (sd, "/m68hc12 > cpu-reset reset /m68hc12/m68hc12eepr"); } + + cpu->hw_cpu = sim_hw_parse (sd, "/m68hc12"); } return 0; } diff --git a/sim/m68hc11/sim-main.h b/sim/m68hc11/sim-main.h index 21c1fc9..a47e7aa 100644 --- a/sim/m68hc11/sim-main.h +++ b/sim/m68hc11/sim-main.h @@ -204,7 +204,9 @@ struct _sim_cpu { uint8 cpu_use_local_config; uint8 ios[MAX_PORTS]; - + + struct hw *hw_cpu; + /* ... base type ... */ sim_cpu_base base; }; @@ -530,6 +532,13 @@ extern void emul_os (int op, sim_cpu *cpu); extern void cpu_interp_m6811 (sim_cpu *cpu); extern void cpu_interp_m6812 (sim_cpu *cpu); +extern int m68hc11cpu_set_oscillator (SIM_DESC sd, const char *port, + double ton, double toff, + signed64 repeat); +extern int m68hc11cpu_clear_oscillator (SIM_DESC sd, const char *port); +extern void m68hc11cpu_set_port (struct hw *me, sim_cpu *cpu, + unsigned addr, uint8 val); + /* The current state of the processor; registers, memory, etc. */ #define CIA_GET(CPU) (cpu_get_pc (CPU)) |