Skip to content

Commit 2ec8a9a

Browse files
Add avr_io_t *avr_io_findinstance function.
Fix ioport state inconsistency after bitbang output.
1 parent c4afbd1 commit 2ec8a9a

File tree

6 files changed

+124
-13
lines changed

6 files changed

+124
-13
lines changed

simavr/sim/avr_bitbang.c

+53-4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extern "C" {
2929

3030
#include <stdio.h>
3131
#include <stdlib.h>
32+
#include <string.h>
3233

3334
#include "avr_bitbang.h"
3435

@@ -99,7 +100,16 @@ static void avr_bitbang_write_bit(avr_bitbang_t *p)
99100

100101
// output to HW pin
101102
if ( p->p_out.port ) {
102-
avr_raise_irq(avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_out.port ), p->p_out.pin), bit);
103+
avr_raise_irq(p->p_out.irq, bit);
104+
uint16_t addr = p->p_out.ioport->r_port;
105+
uint8_t value = p->avr->data[addr];
106+
if (bit)
107+
value |= 1 << p->p_out.pin;
108+
else
109+
value &= ~(1 << p->p_out.pin);
110+
// at least avr->data[addr] update is required, otherwise port state is broken
111+
// also triggering vcd signal would be nice here
112+
avr_core_watch_write(p->avr, addr, value);
103113
}
104114

105115
// module callback
@@ -130,7 +140,16 @@ static void avr_bitbang_clk_edge(avr_bitbang_t *p)
130140

131141
// generate clock output on HW pin
132142
if ( p->clk_generate && p->p_clk.port ) {
133-
avr_raise_irq(avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_clk.port ), p->p_clk.pin), clk);
143+
avr_raise_irq(p->p_clk.irq, clk);
144+
uint16_t addr = p->p_clk.ioport->r_port;
145+
uint8_t value = p->avr->data[addr];
146+
if (clk)
147+
value |= 1 << p->p_clk.pin;
148+
else
149+
value &= ~(1 << p->p_clk.pin);
150+
// at least avr->data[addr] update is required, otherwise port state is broken
151+
// also triggering vcd signal would be nice here
152+
avr_core_watch_write(p->avr, addr, value);
134153
}
135154

136155
if ( phase ) {
@@ -175,6 +194,36 @@ static void avr_bitbang_clk_hook(struct avr_irq_t * irq, uint32_t value, void *
175194
avr_bitbang_clk_edge(p);
176195
}
177196

197+
/**
198+
* define bitbang pins
199+
*
200+
* @param p bitbang structure
201+
* @param clk clock pin
202+
* @param in incoming data pin
203+
* @param out outgoing data pin
204+
*/
205+
void avr_bitbang_defpins(avr_bitbang_t * p, avr_iopin_t *clk, avr_iopin_t *in, avr_iopin_t *out)
206+
{
207+
if (clk) {
208+
p->p_clk.port = clk->port;
209+
p->p_clk.pin = clk->pin;
210+
p->p_clk.ioport = (avr_ioport_t *)avr_io_findinstance(p->avr, "port", clk->port);
211+
p->p_clk.irq = avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_clk.port ), p->p_clk.pin);
212+
}
213+
if (in) {
214+
p->p_in.port = in->port;
215+
p->p_in.pin = in->pin;
216+
p->p_in.ioport = (avr_ioport_t *)avr_io_findinstance(p->avr, "port", in->port);
217+
p->p_in.irq = avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_in.port ), p->p_in.pin);
218+
}
219+
if (out) {
220+
p->p_out.port = out->port;
221+
p->p_out.pin = out->pin;
222+
p->p_out.ioport = (avr_ioport_t *)avr_io_findinstance(p->avr, "port", out->port);
223+
p->p_out.irq = avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_out.port ), p->p_out.pin);
224+
}
225+
}
226+
178227
/**
179228
* reset bitbang sub-module
180229
*
@@ -220,7 +269,7 @@ void avr_bitbang_start(avr_bitbang_t * p)
220269
} else {
221270
// slave mode -> attach clock function to clock pin
222271
///@todo test
223-
avr_irq_register_notify( avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_clk.port ), p->p_clk.pin), avr_bitbang_clk_hook, p);
272+
avr_irq_register_notify( p->p_clk.irq, avr_bitbang_clk_hook, p);
224273
}
225274

226275
}
@@ -238,7 +287,7 @@ void avr_bitbang_stop(avr_bitbang_t * p)
238287

239288
p->enabled = 0;
240289
avr_cycle_timer_cancel(p->avr, avr_bitbang_clk_timer, p);
241-
avr_irq_unregister_notify( avr_io_getirq(p->avr, AVR_IOCTL_IOPORT_GETIRQ( p->p_clk.port ), p->p_clk.pin), avr_bitbang_clk_hook, p);
290+
avr_irq_unregister_notify( p->p_clk.irq, avr_bitbang_clk_hook, p);
242291
}
243292

244293
#ifdef __cplusplus

simavr/sim/avr_bitbang.h

+22-3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,15 @@
4848
#include "avr_ioport.h"
4949

5050

51+
/**
52+
* pin structure
53+
*/
54+
typedef struct avr_bitbang_iopin_t {
55+
uint16_t port : 8; ///< port e.g. 'B'
56+
uint16_t pin : 8; ///< pin number
57+
avr_ioport_t * ioport;
58+
avr_irq_t * irq;
59+
} avr_bitbang_iopin_t;
5160

5261

5362
/// SPI Module initialization and state structure
@@ -73,9 +82,9 @@ typedef struct avr_bitbang_t {
7382
uint32_t (*callback_transfer_finished)(uint32_t data, void *param); ///< callback function to notify about a complete transfer
7483
/// (read received data and write new output data)
7584

76-
avr_iopin_t p_clk; ///< clock pin (optional)
77-
avr_iopin_t p_in; ///< data in pin
78-
avr_iopin_t p_out; ///< data out pin
85+
avr_bitbang_iopin_t p_clk; ///< clock pin (optional)
86+
avr_bitbang_iopin_t p_in; ///< data in pin
87+
avr_bitbang_iopin_t p_out; ///< data out pin
7988

8089
// private data
8190
uint32_t data; ///< data buffer
@@ -92,6 +101,16 @@ typedef struct avr_bitbang_t {
92101
*/
93102
void avr_bitbang_reset(avr_t *avr, avr_bitbang_t * p);
94103

104+
/**
105+
* define bitbang pins
106+
*
107+
* @param p bitbang structure
108+
* @param clk clock pin
109+
* @param in incoming data pin
110+
* @param out outgoing data pin
111+
*/
112+
void avr_bitbang_defpins(avr_bitbang_t * p, avr_iopin_t *clk, avr_iopin_t *in, avr_iopin_t *out);
113+
95114
/**
96115
* start bitbang transfer
97116
*

simavr/sim/avr_spi.c

+6-4
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@ static void avr_spi_bitbang_switch_mode(avr_spi_t * p, uint8_t master)
5656
if (!(p->flags & AVR_SPI_FLAG_IOPIN_DIR_CTRL))
5757
return;
5858
if (master) {
59-
p->bit_bang.p_in = p->p_miso;
60-
p->bit_bang.p_out = p->p_mosi;
59+
//p->bit_bang.p_in = p->p_miso;
60+
//p->bit_bang.p_out = p->p_mosi;
61+
avr_bitbang_defpins(&(p->bit_bang), &(p->p_sck), &(p->p_miso), &(p->p_mosi));
6162
avr_irq_t *irq;
6263
uint32_t irq_val;
6364
irq = avr_io_getirq( p->bit_bang.avr,
@@ -67,8 +68,9 @@ static void avr_spi_bitbang_switch_mode(avr_spi_t * p, uint8_t master)
6768
avr_raise_irq(irq, irq_val);
6869
p->bit_bang.clk_generate = 1;
6970
} else {
70-
p->bit_bang.p_in = p->p_mosi;
71-
p->bit_bang.p_out = p->p_miso;
71+
//p->bit_bang.p_in = p->p_mosi;
72+
//p->bit_bang.p_out = p->p_miso;
73+
avr_bitbang_defpins(&(p->bit_bang), &(p->p_sck), &(p->p_mosi), &(p->p_miso));
7274
avr_irq_t *irq;
7375
uint32_t irq_val;
7476
irq = avr_io_getirq( p->bit_bang.avr,

simavr/sim/avr_spi.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ typedef struct avr_spi_t {
6262
avr_regbit_t cpha; // if zero, sampling on the SCK leading edge
6363
avr_regbit_t spr[4]; // clock divider
6464

65+
avr_iopin_t p_sck; // clock in/out pin
6566
avr_iopin_t p_miso; // data in/out pin
6667
avr_iopin_t p_mosi; // data in/out pin
6768
avr_bitbang_t bit_bang;
@@ -91,7 +92,7 @@ void avr_spi_init(avr_t * avr, avr_spi_t * port);
9192
.cpol = AVR_IO_REGBIT(SPCR ## _name, CPOL ## _name), \
9293
.cpha = AVR_IO_REGBIT(SPCR ## _name, CPHA ## _name), \
9394
\
94-
.bit_bang.p_clk = AVR_IOPIN('B', _p_sck), \
95+
.p_sck = AVR_IOPIN('B', _p_sck), \
9596
.p_miso = AVR_IOPIN('B', _p_miso), \
9697
.p_mosi = AVR_IOPIN('B', _p_mosi), \
9798
.p_ss = AVR_IOPIN(_ss_pin_port, _p_ss), \
@@ -121,7 +122,7 @@ void avr_spi_init(avr_t * avr, avr_spi_t * port);
121122
.cpol = AVR_IO_REGBIT(SPCR, CPOL), \
122123
.cpha = AVR_IO_REGBIT(SPCR, CPHA), \
123124
\
124-
.bit_bang.p_clk = AVR_IOPIN('B', _p_sck), \
125+
.p_sck = AVR_IOPIN('B', _p_sck), \
125126
.p_miso = AVR_IOPIN('B', _p_miso), \
126127
.p_mosi = AVR_IOPIN('B', _p_mosi), \
127128
.p_ss = AVR_IOPIN(_ss_pin_port, _p_ss), \

simavr/sim/sim_io.c

+28
Original file line numberDiff line numberDiff line change
@@ -296,3 +296,31 @@ avr_deallocate_ios(
296296
}
297297
avr->io_port = NULL;
298298
}
299+
300+
avr_io_t *
301+
avr_io_findinstance(
302+
avr_t * avr,
303+
const char * kind,
304+
char name)
305+
{
306+
avr_io_t * io = avr->io_port;
307+
while (io) {
308+
if (!strcmp(io->kind, kind))
309+
{
310+
if (!strcmp(kind, "port") ||
311+
!strcmp(kind, "uart") ||
312+
!strcmp(kind, "usb") ||
313+
!strcmp(kind, "spi") ||
314+
!strcmp(kind, "twi") ||
315+
!strcmp(kind, "timer")) {
316+
avr_io_instance_t * io_inst = (avr_io_instance_t *)io;
317+
if (io_inst->name == name)
318+
return io;
319+
} else {
320+
return io;
321+
}
322+
}
323+
io = io->next;
324+
}
325+
return NULL;
326+
}

simavr/sim/sim_io.h

+12
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,18 @@ avr_io_getirq(
104104
avr_t * avr,
105105
uint32_t ctl,
106106
int index);
107+
typedef struct avr_io_instance_t {
108+
avr_io_t io;
109+
char name;
110+
} avr_io_instance_t;
111+
// finds an IO module instance by its kind (e.g. "port" for ioport, "uart" for usart and so on)
112+
// and (if applicable) symbolic name (e.g. 'B' for ioport, '0' for uart)
113+
avr_io_t *
114+
avr_io_findinstance(
115+
avr_t * avr,
116+
const char * kind,
117+
char name);
118+
107119

108120
// get the IRQ for an absolute IO address
109121
// this allows any code to hook an IRQ in any io address, for example

0 commit comments

Comments
 (0)