1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-13 22:32:03 +00:00

Corrects CMPI and documentation; implements JMP.

This commit is contained in:
Thomas Harte 2019-03-31 21:13:26 -04:00
parent cb240cd32a
commit c6f977ed4b
3 changed files with 132 additions and 54 deletions

View File

@ -196,6 +196,11 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
overflow_flag_ = (source ^ destination) & (destination ^ result) & 0x80000000; overflow_flag_ = (source ^ destination) & (destination ^ result) & 0x80000000;
} break; } break;
// JMP: copies the source to the program counter.
case Operation::JMP:
program_counter_.full = active_program_->source->full;
break;
/* /*
MOVE.b, MOVE.l and MOVE.w: move the least significant byte or word, or the entire long word, MOVE.b, MOVE.l and MOVE.w: move the least significant byte or word, or the entire long word,
and set negative, zero, overflow and carry as appropriate. and set negative, zero, overflow and carry as appropriate.
@ -364,6 +369,19 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
} }
break; break;
case int(MicroOp::Action::CalcD16PC) | MicroOp::SourceMask:
effective_address_[0] = int16_t(prefetch_queue_.halves.low.full) + program_counter_.full;
break;
case int(MicroOp::Action::CalcD16PC) | MicroOp::DestinationMask:
effective_address_[1] = int16_t(prefetch_queue_.halves.low.full) + program_counter_.full;
break;
case int(MicroOp::Action::CalcD16PC) | MicroOp::SourceMask | MicroOp::DestinationMask:
effective_address_[0] = int16_t(prefetch_queue_.halves.high.full) + program_counter_.full;
effective_address_[1] = int16_t(prefetch_queue_.halves.low.full) + program_counter_.full;
break;
case int(MicroOp::Action::CalcD16An) | MicroOp::SourceMask: case int(MicroOp::Action::CalcD16An) | MicroOp::SourceMask:
effective_address_[0] = int16_t(prefetch_queue_.halves.low.full) + active_program_->source->full; effective_address_[0] = int16_t(prefetch_queue_.halves.low.full) + active_program_->source->full;
break; break;
@ -422,19 +440,32 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
case int(MicroOp::Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask: case int(MicroOp::Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask:
// Assumption: this will be assembling right at the start of the instruction. // Assumption: this will be assembling right at the start of the instruction.
bus_data_[0] = prefetch_queue_.halves.low.full; source_bus_data_[0] = prefetch_queue_.halves.low.full;
break; break;
case int(MicroOp::Action::AssembleWordDataFromPrefetch) | MicroOp::DestinationMask: case int(MicroOp::Action::AssembleWordDataFromPrefetch) | MicroOp::DestinationMask:
bus_data_[1] = prefetch_queue_.halves.low.full; destination_bus_data_[0] = prefetch_queue_.halves.low.full;
break; break;
case int(MicroOp::Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask: case int(MicroOp::Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask:
bus_data_[0] = prefetch_queue_.full; source_bus_data_[0] = prefetch_queue_.full;
break; break;
case int(MicroOp::Action::AssembleLongWordDataFromPrefetch) | MicroOp::DestinationMask: case int(MicroOp::Action::AssembleLongWordDataFromPrefetch) | MicroOp::DestinationMask:
bus_data_[1] = prefetch_queue_.full; destination_bus_data_[0] = prefetch_queue_.full;
break;
case int(MicroOp::Action::CopyToEffectiveAddress) | MicroOp::SourceMask:
effective_address_[0] = *active_program_->source;
break;
case int(MicroOp::Action::CopyToEffectiveAddress) | MicroOp::DestinationMask:
effective_address_[1] = *active_program_->destination;
break;
case int(MicroOp::Action::CopyToEffectiveAddress) | MicroOp::SourceMask | MicroOp::DestinationMask:
effective_address_[0] = *active_program_->source;
effective_address_[1] = *active_program_->destination;
break; break;
} }

View File

@ -47,26 +47,35 @@ struct ProcessorStorageConstructor {
during this program. This should follow the same general pattern as during this program. This should follow the same general pattern as
those in yacht.txt; full description below. those in yacht.txt; full description below.
@discussion @param addresses A vector of the addresses to place on the bus coincident
The access pattern is defined, as in yacht.txt, to be a string consisting with those acess steps that require them.
of the following discrete bus actions. Spaces are ignored.
* n: no operation; data bus is not used; @param read_full_words @c true to indicate that read and write operations are
* -: idle state; data bus is not used but is also not available; selecting a full word; @c false to signal byte accesses only.
* p: program fetch; reads from the PC and adds two to it;
* W: write MSW of something onto the bus; @discussion
* w: write LSW of something onto the bus; The access pattern is defined to correlate closely to that in yacht.txt; it is
* R: read MSW of something from the bus; a space-separated sequence of the following actions:
* r: read LSW of soemthing from the bus;
* S: push the MSW of something onto the stack; * n: no operation for four cycles; data bus is not used;
* s: push the LSW of something onto the stack; * nn: no operation for eight cycles; data bus is not used;
* U: pop the MSW of something from the stack; * np: program fetch; reads from the PC and adds two to it, advancing the prefetch queue;
* u: pop the LSW of something from the stack; * nW: write MSW of something onto the bus;
* V: fetch a vector's MSW; * nw: write LSW of something onto the bus;
* v: fetch a vector's LSW; * nR: read MSW of something from the bus into the source latch;
* nr: read LSW of soemthing from the bus into the source latch;
* nRd: read MSW of something from the bus into the destination latch;
* nrd: read LSW of soemthing from the bus into the destination latch;
* nS: push the MSW of something onto the stack;
* ns: push the LSW of something onto the stack;
* nU: pop the MSW of something from the stack;
* nu: pop the LSW of something from the stack;
* nV: fetch a vector's MSW;
* nv: fetch a vector's LSW;
* i: acquire interrupt vector in an IACK cycle; * i: acquire interrupt vector in an IACK cycle;
* F: fetch the SSPs MSW; * nF: fetch the SSPs MSW;
* f: fetch the SSP's LSW. * nf: fetch the SSP's LSW;
* _: hold the reset line active for the usual period.
Quite a lot of that is duplicative, implying both something about internal Quite a lot of that is duplicative, implying both something about internal
state and something about what's observable on the bus, but it's helpful to state and something about what's observable on the bus, but it's helpful to
@ -82,8 +91,6 @@ struct ProcessorStorageConstructor {
*/ */
size_t assemble_program(std::string access_pattern, const std::vector<uint32_t *> &addresses = {}, bool read_full_words = true) { size_t assemble_program(std::string access_pattern, const std::vector<uint32_t *> &addresses = {}, bool read_full_words = true) {
auto address_iterator = addresses.begin(); auto address_iterator = addresses.begin();
RegisterPair32 *scratch_data_read = storage_.bus_data_;
RegisterPair32 *scratch_data_write = storage_.bus_data_;
using Action = BusStep::Action; using Action = BusStep::Action;
std::vector<BusStep> steps; std::vector<BusStep> steps;
@ -162,14 +169,15 @@ struct ProcessorStorageConstructor {
} }
// A standard read or write. // A standard read or write.
if(token == "nR" || token == "nr" || token == "nW" || token == "nw") { if(token == "nR" || token == "nr" || token == "nW" || token == "nw" || token == "nRd" || token == "nrd") {
const bool is_read = tolower(access_pattern[1]) == 'r'; const bool is_read = tolower(token[1]) == 'r';
RegisterPair32 **scratch_data = is_read ? &scratch_data_read : &scratch_data_write; const bool use_source_storage = is_read && token.size() != 3;
RegisterPair32 *scratch_data = use_source_storage ? &storage_.source_bus_data_[0] : &storage_.destination_bus_data_[0];
step.microcycle.length = HalfCycles(5); step.microcycle.length = HalfCycles(5);
step.microcycle.operation = Microcycle::NewAddress | (is_read ? Microcycle::Read : 0); step.microcycle.operation = Microcycle::NewAddress | (is_read ? Microcycle::Read : 0);
step.microcycle.address = *address_iterator; step.microcycle.address = *address_iterator;
step.microcycle.value = isupper(token[1]) ? &(*scratch_data)->halves.high : &(*scratch_data)->halves.low; step.microcycle.value = isupper(token[1]) ? &scratch_data->halves.high : &scratch_data->halves.low;
steps.push_back(step); steps.push_back(step);
step.microcycle.length = HalfCycles(3); step.microcycle.length = HalfCycles(3);
@ -182,8 +190,7 @@ struct ProcessorStorageConstructor {
} }
steps.push_back(step); steps.push_back(step);
if(!isupper(access_pattern[1])) { if(!isupper(token[1])) {
++(*scratch_data);
++address_iterator; ++address_iterator;
} }
@ -241,7 +248,8 @@ struct ProcessorStorageConstructor {
Bcc, // twelve lowest bits are ignored, only a PerformAction is scheduled Bcc, // twelve lowest bits are ignored, only a PerformAction is scheduled
LEA, // decodes register, mode, register LEA, // decodes register, mode, register
MOVEq, // decodes just a destination register MOVEq, // decodes just a destination register
RESET, // no further decoding applied RESET, // no further decoding applied, performs reset cycle
JMP, // six lowest bits are [mode, register], decoding to JMP
}; };
using Operation = ProcessorStorage::Operation; using Operation = ProcessorStorage::Operation;
@ -294,6 +302,8 @@ struct ProcessorStorageConstructor {
{0xf100, 0x7000, Operation::MOVEq, Decoder::MOVEq}, // 4-134 (p238) {0xf100, 0x7000, Operation::MOVEq, Decoder::MOVEq}, // 4-134 (p238)
{0xffff, 0x4e70, Operation::None, Decoder::RESET}, // 6-83 (p537) {0xffff, 0x4e70, Operation::None, Decoder::RESET}, // 6-83 (p537)
{0xffc0, 0x4ec0, Operation::JMP, Decoder::JMP}, // 4-108 (p212)
}; };
std::vector<size_t> micro_op_pointers(65536, std::numeric_limits<size_t>::max()); std::vector<size_t> micro_op_pointers(65536, std::numeric_limits<size_t>::max());
@ -335,8 +345,8 @@ struct ProcessorStorageConstructor {
const int source = instruction & 7; const int source = instruction & 7;
if(instruction & 8) { if(instruction & 8) {
storage_.instructions[instruction].source = &storage_.bus_data_[0]; storage_.instructions[instruction].source = &storage_.source_bus_data_[0];
storage_.instructions[instruction].destination = &storage_.bus_data_[1]; storage_.instructions[instruction].destination = &storage_.destination_bus_data_[0];
op( int(Action::Decrement1) | MicroOp::SourceMask | MicroOp::DestinationMask, op( int(Action::Decrement1) | MicroOp::SourceMask | MicroOp::DestinationMask,
seq("n nr nr np nw", { &storage_.address_[source].full, &storage_.address_[destination].full, &storage_.address_[destination].full }, false)); seq("n nr nr np nw", { &storage_.address_[source].full, &storage_.address_[destination].full, &storage_.address_[destination].full }, false));
@ -355,7 +365,7 @@ struct ProcessorStorageConstructor {
const auto destination_mode = source_mode; const auto destination_mode = source_mode;
const auto destination_register = source_register; const auto destination_register = source_register;
storage_.instructions[instruction].source = &storage_.bus_data_[0]; storage_.instructions[instruction].source = &storage_.source_bus_data_[0];
storage_.instructions[instruction].set_destination(storage_, destination_mode, destination_register); storage_.instructions[instruction].set_destination(storage_, destination_mode, destination_register);
const bool is_byte_access = mapping.operation == Operation::CMPb; const bool is_byte_access = mapping.operation == Operation::CMPb;
@ -375,7 +385,7 @@ struct ProcessorStorageConstructor {
case 0x002: // CMPI.bw #, (An) case 0x002: // CMPI.bw #, (An)
case 0x003: // CMPI.bw #, (An)+ case 0x003: // CMPI.bw #, (An)+
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np nr np", { &storage_.address_[destination_register].full }, !is_byte_access)); op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np nrd np", { &storage_.address_[destination_register].full }, !is_byte_access));
if(mode == 0x3) { if(mode == 0x3) {
op(int(is_byte_access ? Action::Increment1 : Action::Increment2) | MicroOp::DestinationMask); op(int(is_byte_access ? Action::Increment1 : Action::Increment2) | MicroOp::DestinationMask);
} }
@ -385,7 +395,7 @@ struct ProcessorStorageConstructor {
case 0x102: // CMPI.l #, (An) case 0x102: // CMPI.l #, (An)
case 0x103: // CMPI.l #, (An)+ case 0x103: // CMPI.l #, (An)+
op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, seq("np")); op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, seq("np"));
op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np nR nr np", { &storage_.effective_address_[1].full })); op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np nRd nrd np", { &storage_.effective_address_[1].full }));
if(mode == 0x103) { if(mode == 0x103) {
op(int(Action::Increment4) | MicroOp::DestinationMask); op(int(Action::Increment4) | MicroOp::DestinationMask);
} }
@ -394,14 +404,14 @@ struct ProcessorStorageConstructor {
case 0x004: // CMPI.bw #, -(An) case 0x004: // CMPI.bw #, -(An)
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np n")); op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np n"));
op(int(is_byte_access ? Action::Decrement1 : Action::Decrement1) | MicroOp::DestinationMask, seq("nr np", { &storage_.address_[destination_register].full })); op(int(is_byte_access ? Action::Decrement1 : Action::Decrement1) | MicroOp::DestinationMask, seq("nrd np", { &storage_.address_[destination_register].full }));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
case 0x104: // CMPI.l #, -(An) case 0x104: // CMPI.l #, -(An)
op(int(Action::Decrement4) | MicroOp::DestinationMask, seq("np")); op(int(Action::Decrement4) | MicroOp::DestinationMask, seq("np"));
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np n")); op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np n"));
op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, seq("nR nr np", { &storage_.effective_address_[1].full })); op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, seq("nRd nrd np", { &storage_.effective_address_[1].full }));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
@ -411,7 +421,7 @@ struct ProcessorStorageConstructor {
case 0x006: // CMPI.bw #, (d8, An, Xn) case 0x006: // CMPI.bw #, (d8, An, Xn)
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np")); op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np"));
op( calc_action_for_mode(mode) | MicroOp::DestinationMask, op( calc_action_for_mode(mode) | MicroOp::DestinationMask,
seq(pseq("nr np", mode), { &storage_.effective_address_[1].full }, !is_byte_access)); seq(pseq("nrd np", mode), { &storage_.effective_address_[1].full }, !is_byte_access));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
@ -422,33 +432,33 @@ struct ProcessorStorageConstructor {
op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, seq("np")); op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, seq("np"));
op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np")); op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np"));
op( calc_action_for_mode(mode) | MicroOp::DestinationMask, op( calc_action_for_mode(mode) | MicroOp::DestinationMask,
seq(pseq("np nR nr np", mode), { &storage_.effective_address_[1].full })); seq(pseq("np nRd nrd np", mode), { &storage_.effective_address_[1].full }));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
case 0x010: // CMPI.bw #, (xxx).w case 0x010: // CMPI.bw #, (xxx).w
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np")); op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np"));
op(int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nr np", { &storage_.effective_address_[1].full }, !is_byte_access)); op(int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nrd np", { &storage_.effective_address_[1].full }, !is_byte_access));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
case 0x110: // CMPI.l #, (xxx).w case 0x110: // CMPI.l #, (xxx).w
op(Action::None, seq("np")); op(Action::None, seq("np"));
op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np np")); op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np np"));
op(int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("nR nr np", { &storage_.effective_address_[1].full })); op(int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("nRd nrd np", { &storage_.effective_address_[1].full }));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
case 0x011: // CMPI.bw #, (xxx).l case 0x011: // CMPI.bw #, (xxx).l
op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np np")); op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np np"));
op(int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nr np", { &storage_.effective_address_[1].full }, !is_byte_access)); op(int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nrd np", { &storage_.effective_address_[1].full }, !is_byte_access));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
case 0x111: // CMPI.l #, (xxx).l case 0x111: // CMPI.l #, (xxx).l
op(Action::None, seq("np")); op(Action::None, seq("np"));
op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np np")); op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np np"));
op(int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nR nr np", { &storage_.effective_address_[1].full })); op(int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask, seq("np nRd nrd np", { &storage_.effective_address_[1].full }));
op(Action::PerformOperation); op(Action::PerformOperation);
break; break;
@ -456,6 +466,41 @@ struct ProcessorStorageConstructor {
} }
} break; } break;
case Decoder::JMP: {
storage_.instructions[instruction].source = &storage_.effective_address_[0];
const int mode = combined_mode(source_mode, source_register);
switch(mode) {
default: continue;
case 0x02: // JMP (An)
storage_.instructions[instruction].source = &storage_.address_[source_register];
op(Action::PerformOperation, seq("np np"));
break;
case 0x12: // JMP (d16, PC)
case 0x05: // JMP (d16, An)
op(calc_action_for_mode(mode) | MicroOp::SourceMask, seq("n np np", { &storage_.effective_address_[0].full }));
op(Action::PerformOperation);
break;
case 0x13: // JMP (d8, PC, Xn)
case 0x06: // JMP (d8, An, Xn)
op(calc_action_for_mode(mode) | MicroOp::SourceMask, seq("n nn np np", { &storage_.effective_address_[0].full }));
op(Action::PerformOperation);
break;
case 0x10: // JMP (xxx).W
op(int(MicroOp::Action::AssembleWordAddressFromPrefetch) | MicroOp::SourceMask);
op(Action::PerformOperation, seq("n np np"));
break;
case 0x11: // JMP (xxx).L
op(Action::None, seq("np"));
op(int(MicroOp::Action::AssembleLongWordAddressFromPrefetch) | MicroOp::SourceMask);
op(Action::PerformOperation, seq("np np"));
break;
}
} break;
case Decoder::LEA: { case Decoder::LEA: {
const int destination_register = (instruction >> 9) & 7; const int destination_register = (instruction >> 9) & 7;
storage_.instructions[instruction].destination = &storage_.address_[destination_register]; storage_.instructions[instruction].destination = &storage_.address_[destination_register];
@ -581,7 +626,7 @@ struct ProcessorStorageConstructor {
break; break;
default: // (An), (An)+, -(An), (d16, An), (d8, An Xn), (xxx).W, (xxx).L default: // (An), (An)+, -(An), (d16, An), (d8, An Xn), (xxx).W, (xxx).L
storage_.instructions[instruction].source = &storage_.bus_data_[0]; storage_.instructions[instruction].source = &storage_.source_bus_data_[0];
break; break;
} }
@ -595,7 +640,7 @@ struct ProcessorStorageConstructor {
break; break;
default: // (An), (An)+, -(An), (d16, An), (d8, An Xn), (xxx).W, (xxx).L default: // (An), (An)+, -(An), (d16, An), (d8, An Xn), (xxx).W, (xxx).L
storage_.instructions[instruction].destination = &storage_.bus_data_[1]; storage_.instructions[instruction].destination = &storage_.destination_bus_data_[0];
break; break;
} }
@ -1126,6 +1171,7 @@ struct ProcessorStorageConstructor {
} break; } break;
case Decoder::RESET: case Decoder::RESET:
storage_.instructions[instruction].requires_supervisor = true;
op(Action::None, seq("nn _ np")); op(Action::None, seq("nn _ np"));
break; break;

View File

@ -37,7 +37,8 @@ class ProcessorStorage {
// Generic sources and targets for memory operations; // Generic sources and targets for memory operations;
// by convention: [0] = source, [1] = destination. // by convention: [0] = source, [1] = destination.
RegisterPair32 effective_address_[2]; RegisterPair32 effective_address_[2];
RegisterPair32 bus_data_[2]; RegisterPair32 source_bus_data_[1];
RegisterPair32 destination_bus_data_[1];
HalfCycles half_cycles_left_to_run_; HalfCycles half_cycles_left_to_run_;
@ -53,7 +54,7 @@ class ProcessorStorage {
CMPb, CMPw, CMPl, CMPb, CMPw, CMPl,
BRA, Bcc, BRA, Bcc, JMP
}; };
/*! /*!
@ -211,7 +212,7 @@ class ProcessorStorage {
switch(mode) { switch(mode) {
case 0: source = &storage.data_[reg]; break; case 0: source = &storage.data_[reg]; break;
case 1: source = &storage.address_[reg]; break; case 1: source = &storage.address_[reg]; break;
default: source = &storage.bus_data_[0]; break; default: source = &storage.source_bus_data_[0]; break;
} }
} }
@ -219,7 +220,7 @@ class ProcessorStorage {
switch(mode) { switch(mode) {
case 0: destination = &storage.data_[reg]; break; case 0: destination = &storage.data_[reg]; break;
case 1: destination = &storage.address_[reg]; break; case 1: destination = &storage.address_[reg]; break;
default: destination = &storage.bus_data_[1]; break; default: destination = &storage.destination_bus_data_[0]; break;
} }
} }
}; };